openclaw - ✅(Solved) Fix [Bug]: Telegram /approve allow-always writes 'source' field that openclaw approvals set --gateway rejects — allowlist updates silently fail to persist to gateway [3 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Telegram "Allow always" approvals write an allowlist entry with a source: "allow-always" string field. The file write to ~/.openclaw/exec-approvals.json succeeds, but openclaw approvals set --gateway --file <path> then rejects every entry containing source with invalid exec.approvals.set params: unexpected property 'source'. The gateway never receives the new policy. User-visible symptom: "Allow always" silently fails to persist.

Error Message

  1. Observe the rejection error listing every entry containing source. Error is truncated at terminal output width. One rejection is emitted per allowlist entry containing source. No policy update reaches the gateway; on-disk file and gateway in-memory state drift apart. Full error text attached as bug-source-field-error.txt. bug-source-field-error.txt Attached: bug-source-field-error.txt — full rejection error from openclaw approvals set --gateway --file.

Root Cause

Telegram "Allow always" approvals write an allowlist entry with a source: "allow-always" string field. The file write to ~/.openclaw/exec-approvals.json succeeds, but openclaw approvals set --gateway --file <path> then rejects every entry containing source with invalid exec.approvals.set params: unexpected property 'source'. The gateway never receives the new policy. User-visible symptom: "Allow always" silently fails to persist.

Fix Action

Fix / Workaround

Affected: any install where users tap "Allow always" on Telegram exec approval prompts. Severity: High — silently breaks the persistence contract of "Allow always" and causes unbounded drift between on-disk allowlist and gateway in-memory state. Frequency: Every "Allow always" tap produces an unpushable entry. Deterministic, 100% reproduction on my install. Consequence: Users experience "OpenClaw isn't remembering my approvals." Any automation that reads ~/.openclaw/exec-approvals.json and pushes it to the gateway breaks on the first Telegram-originated entry. Workaround is a strip pass over every entry before every gateway push.

Last known good version: unknown — "Allow always" may never have worked cleanly against the gateway on this install. I adopted the strip-before-push workaround early and never had a period of normal operation to compare against. If the gateway schema was ever widened to accept source, that change is not visible to me from the CLI behavior alone.

Workaround in use: sync script strips source from every allowlist entry before every openclaw approvals set --gateway --file call. This has kept the system functional but means ~/.openclaw/exec-approvals.json on disk drifts from what actually reaches the gateway.

PR fix notes

PR #69529: fix: prevent defaultAccountId leak in cross-provider message sends

Description (problem / solution / changelog)

Summary

Two bug fixes bundled in this PR:


Fix 1: #69525 — Cross-provider message send leaks source session accountId to target channel

When sending messages across providers (e.g. Telegram → Feishu) with allowAcrossProviders: true, the source session's defaultAccountId was incorrectly propagated to the target channel plugin, which has no account registered under that name.

File: src/infra/outbound/message-action-runner.ts

const explicitlyProvidedAccountId = readStringParam(params, "accountId");
const allowAcrossProviders = cfg.tools?.message?.crossContext?.allowAcrossProviders === true;
const isCrossProvider = Boolean(
  allowAcrossProviders &&
    input.toolContext?.currentChannelProvider &&
    input.toolContext.currentChannelProvider !== channel,
);
let accountId = explicitlyProvidedAccountId ?? (isCrossProvider ? undefined : input.defaultAccountId);

Fix 2: #69482 — Telegram "Allow always" source field rejected by gateway

Telegram "Allow always" approval handler writes source: "allow-always", but the gateway schema for exec.approvals.set didn't include this field, causing openclaw approvals set --gateway to reject entries with unexpected property 'source'.

File: src/gateway/protocol/schema/exec-approvals.ts

Added source: Type.Optional(Type.String()) to ExecApprovalsAllowlistEntrySchema.


Also included: #69475 (partial) — Skill description fixes

Updated SKILL.md description fields for gog and session-logs to include Use when: trigger conditions per the Anthropic skill spec.

Files: skills/gog/SKILL.md, skills/session-logs/SKILL.md

Changed files

  • skills/gog/SKILL.md (modified, +1/-1)
  • skills/session-logs/SKILL.md (modified, +1/-1)
  • src/gateway/protocol/schema/exec-approvals.ts (modified, +3/-0)
  • src/infra/outbound/message-action-runner.test.ts (modified, +66/-0)
  • src/infra/outbound/message-action-runner.ts (modified, +13/-1)

PR #2: fix(cron): validate announce account ids

Description (problem / solution / changelog)

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

Summary

  • Problem: cron.add and cron.update validated announce channels but still accepted explicit delivery.accountId values that do not exist for the chosen channel.
  • Why it matters: operators can create or patch cron jobs that look valid at write time but are guaranteed to fail or misroute at delivery time.
  • What changed: src/gateway/server-methods/cron.ts now validates explicit announce accountId values against configured accounts for the resolved channel, including failure destinations that use announce mode.
  • What did NOT change (scope boundary): delivery execution, account auto-resolution, and cron transport behavior were not changed; this is creation/update-time validation only.
  • AI-assisted: Yes. I implemented the fix and ran the scoped verification locally in this workspace.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #69513
  • Related #69482
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: cron request validation checked that announce delivery channels were configured, but it never checked whether an explicitly provided account id belonged to that configured channel.
  • Missing detection / guardrail: gateway RPC tests covered channel validation but not invalid explicit announce account ids on add/update.
  • Contributing context (if known): multi-account channels make this more likely because a typo still looks syntactically valid and gets persisted unchanged.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server.cron.test.ts
  • Scenario the test should lock in: cron.add and cron.update reject announce deliveries whose explicit accountId is not configured for the selected channel.
  • Why this is the smallest reliable guardrail: the bug lives in gateway request validation, so the RPC test file exercises the real user-facing contract without needing full cron execution.
  • Existing test that already covers this (if any): none.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

  • openclaw cron create and equivalent gateway cron.add / cron.update calls now reject invalid explicit announce account ids instead of storing a broken delivery target.

Diagram (if applicable)

Before:
[cron add/update with announce channel + bad accountId] -> [stored successfully] -> [later delivery failure/misroute]

After:
[cron add/update with announce channel + bad accountId] -> [gateway validation rejects request] -> [operator fixes accountId before save]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: Ubuntu Linux in Cursor Cloud
  • Runtime/container: Node 22 + pnpm workspace
  • Model/provider: N/A
  • Integration/channel (if any): Gateway cron RPC validation
  • Relevant config (redacted): test config with Telegram announce channel enabled

Steps

  1. Configure a channel with one valid account.
  2. Call cron.add or cron.update with delivery.mode="announce", that channel, and a nonexistent accountId.
  3. Observe gateway response.

Expected

  • The gateway rejects the request before persisting the job.

Actual

  • Before this fix, the gateway accepted and stored the invalid account id unchanged.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: ran pnpm test src/gateway/server.cron.test.ts; ran pnpm check:changed.
  • Edge cases checked: add and update both reject invalid explicit announce account ids; existing announce channel validation remains intact.
  • What you did not verify: live cron execution against a real multi-account channel deployment.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: configs that rely on implicit fallback behavior for malformed explicit account ids will now fail fast at write time.
    • Mitigation: validation only applies when an explicit non-empty accountId is provided; existing implicit/default-account flows are unchanged.
<!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-a225a134-d59a-46cf-a2c4-14c5aaa6297d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-a225a134-d59a-46cf-a2c4-14c5aaa6297d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

Changed files

  • src/gateway/server-methods/cron.ts (modified, +78/-8)
  • src/gateway/server.cron.test.ts (modified, +371/-0)

PR #3: fix(approvals): accept allow-always source metadata

Description (problem / solution / changelog)

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->

Summary

  • Problem: Telegram/native allow-always approvals already persist allowlist entries with source: "allow-always", but the gateway exec.approvals.set schema rejected that field as unexpected.
  • Why it matters: local approvals files and the gateway push path disagree on the allowlist contract, so gateway sync can fail even when the on-disk approvals file is valid for the runtime.
  • What changed: src/gateway/protocol/schema/exec-approvals.ts now accepts optional source: "allow-always" on allowlist entries, matching the existing persisted approvals type.
  • What did NOT change (scope boundary): no approval decision logic, persistence behavior, or Telegram/native reply handling changed in this PR; it only aligns the gateway protocol schema with existing stored data.
  • AI-assisted: Yes. I implemented the protocol fix and verified it locally with targeted tests and changed-scope checks.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #69482
  • Related #69478
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: the durable approvals store type and normalization path already preserved source: "allow-always", but the gateway protocol schema for exec.approvals.set and exec.approvals.node.set did not allow that field.
  • Missing detection / guardrail: there was no validator regression test covering a real allowlist payload that included source: "allow-always".
  • Contributing context (if known): the issue report shows this surfaced through Telegram "Allow always", but the mismatch is fundamentally between persisted approvals data and the gateway wire contract.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/protocol/index.test.ts
  • Scenario the test should lock in: validateExecApprovalsSetParams and validateExecApprovalsNodeSetParams accept allowlist entries that include source: "allow-always".
  • Why this is the smallest reliable guardrail: the bug is a protocol/schema rejection, so validator tests hit the exact contract boundary that failed without needing a live Telegram or gateway sync flow.
  • Existing test that already covers this (if any): none.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

  • Gateway approval set payloads may now include persisted allow-always source metadata without being rejected as invalid.

Diagram (if applicable)

Before:
[allowlist entry with source="allow-always"] -> [exec.approvals.set validator] -> [reject unexpected property]

After:
[allowlist entry with source="allow-always"] -> [exec.approvals.set validator] -> [accept payload]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: Ubuntu Linux in Cursor Cloud
  • Runtime/container: Node 22 + pnpm workspace
  • Model/provider: N/A
  • Integration/channel (if any): Gateway exec approvals protocol validation
  • Relevant config (redacted): approvals payload with allowlist entry { pattern: "/usr/bin/curl", source: "allow-always" }

Steps

  1. Construct an approvals file payload containing an allowlist entry with source: "allow-always".
  2. Validate it through the gateway protocol path for exec.approvals.set or exec.approvals.node.set.
  3. Observe whether the validator accepts or rejects the payload.

Expected

  • The gateway protocol should accept allowlist entries that match the already-persisted approvals type, including source: "allow-always".

Actual

  • Before this fix, the schema rejected the payload because source was not part of ExecApprovalsAllowlistEntrySchema.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: ran pnpm test src/gateway/protocol/index.test.ts; ran pnpm check:changed.
  • Edge cases checked: both gateway set and node set validators accept allow-always source metadata; no unrelated schema fields were broadened.
  • What you did not verify: live Telegram approval flow or a real openclaw approvals set --gateway round-trip against a running gateway.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: this only fixes the schema mismatch slice of the issue; if another runtime path strips or mishandles source, that would need follow-up.
    • Mitigation: this PR is intentionally scoped to the concrete validator rejection, and the new tests lock the contract in place.
<!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-a225a134-d59a-46cf-a2c4-14c5aaa6297d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-a225a134-d59a-46cf-a2c4-14c5aaa6297d"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

Changed files

  • src/gateway/protocol/index.test.ts (modified, +45/-1)
  • src/gateway/protocol/schema/exec-approvals.ts (modified, +1/-0)

Code Example

Attached: bug-source-field-error.txt — full rejection error from `openclaw approvals set --gateway --file`.

Secondary finding worth noting: `openclaw approvals set` WITHOUT --gateway accepts files containing `source` without complaint and writes them through to disk. Only the --gateway path rejects. The two modes disagree about what constitutes a valid allowlist shape.

Related: #69478 (enqueueSystemEvent duplicate-approval cascade). Distinct bug but same subsystem and same user-visible symptom ("my approvals don't stick"). A user hitting both simultaneously cannot distinguish them without reading gateway logs.
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Telegram "Allow always" approvals write an allowlist entry with a source: "allow-always" string field. The file write to ~/.openclaw/exec-approvals.json succeeds, but openclaw approvals set --gateway --file <path> then rejects every entry containing source with invalid exec.approvals.set params: unexpected property 'source'. The gateway never receives the new policy. User-visible symptom: "Allow always" silently fails to persist.

Steps to reproduce

  1. On an install with a Telegram binding configured with directPolicy: "allow", trigger an exec approval prompt from any agent (any exec call that hits on-miss under the current allowlist).

  2. In Telegram, tap "Allow always" on the inline button.

  3. Inspect the resulting allowlist entry in ~/.openclaw/exec-approvals.json. Example captured from a production install:

    { "pattern": "/usr/bin/curl", "lastUsedAt": 1776563902217, "id": "ed8f2b4b-20be-4965-bf23-9701d3cd6e1d", "lastUsedCommand": "curl -s http://localhost:8000/health", "lastResolvedPath": "/usr/bin/curl", "source": "allow-always" }

  4. Attempt to push the file to the gateway:

    openclaw approvals set --gateway --file ~/.openclaw/exec-approvals.json

  5. Observe the rejection error listing every entry containing source.

Minimal synthetic reproducer (does not require Telegram): construct any allowlist entry with a literal source: "allow-always" field and push via --gateway. Same rejection occurs.

Expected behavior

Either the gateway schema accepts source as an optional string property on allowlist entries (preferred — since Telegram's own approval handler writes it, the schema should describe what's actually on disk), OR the Telegram approval handler stops writing a field the gateway will reject. Whatever the fix, openclaw approvals set (local write) and openclaw approvals set --gateway (gateway push) should agree on the schema — currently the local-write path accepts source without complaint while the gateway path rejects it.

Actual behavior

openclaw approvals set --gateway --file ~/.openclaw/exec-approvals.json exits nonzero with:

invalid exec.approvals.set params: at /file/agents/maelcum/allowlist/5: unexpected property 'source'; at /file/agents/maelcum/allowlist/6: unexpected property 'source'; at /file/agents/maelcum/allowlist/7: unexpected property 'source'; at /file/agents/maelcum/allowlist/8: unexpected property 'source...

Error is truncated at terminal output width. One rejection is emitted per allowlist entry containing source. No policy update reaches the gateway; on-disk file and gateway in-memory state drift apart. Full error text attached as bug-source-field-error.txt.

bug-source-field-error.txt

OpenClaw version

2026.4.14 (323493f)

Operating system

macOS 26.4.1

Install method

npm global, latest stable as of filing

Model

N/A — bug is in approvals subsystem, not model-dependent

Provider / routing chain

N/A — bug is in approvals subsystem, not provider-dependent

Additional provider/model setup details

Host: Mac Mini M4 Pro, 48 GB unified memory. Gateway supervised by launchd, loopback bind on port 18789. Telegram binding has dmPolicy: "allowlist" with directPolicy: "allow" — so exec approvals are being requested and "Allow always" is a real user-facing flow on this install. Over ~3 weeks of normal use, 13 allowlist entries across 8 agent scopes accumulated the source: "allow-always" field, rendering the whole allowlist un-pushable without a strip pass.

Logs, screenshots, and evidence

Attached: bug-source-field-error.txt — full rejection error from `openclaw approvals set --gateway --file`.

Secondary finding worth noting: `openclaw approvals set` WITHOUT --gateway accepts files containing `source` without complaint and writes them through to disk. Only the --gateway path rejects. The two modes disagree about what constitutes a valid allowlist shape.

Related: #69478 (enqueueSystemEvent duplicate-approval cascade). Distinct bug but same subsystem and same user-visible symptom ("my approvals don't stick"). A user hitting both simultaneously cannot distinguish them without reading gateway logs.

Impact and severity

Affected: any install where users tap "Allow always" on Telegram exec approval prompts. Severity: High — silently breaks the persistence contract of "Allow always" and causes unbounded drift between on-disk allowlist and gateway in-memory state. Frequency: Every "Allow always" tap produces an unpushable entry. Deterministic, 100% reproduction on my install. Consequence: Users experience "OpenClaw isn't remembering my approvals." Any automation that reads ~/.openclaw/exec-approvals.json and pushes it to the gateway breaks on the first Telegram-originated entry. Workaround is a strip pass over every entry before every gateway push.

Additional information

Last known good version: unknown — "Allow always" may never have worked cleanly against the gateway on this install. I adopted the strip-before-push workaround early and never had a period of normal operation to compare against. If the gateway schema was ever widened to accept source, that change is not visible to me from the CLI behavior alone.

Workaround in use: sync script strips source from every allowlist entry before every openclaw approvals set --gateway --file call. This has kept the system functional but means ~/.openclaw/exec-approvals.json on disk drifts from what actually reaches the gateway.

extent analysis

TL;DR

The openclaw approvals set --gateway command rejects allowlist entries containing a source field, causing the gateway to not receive the new policy, and this can be fixed by either modifying the gateway schema to accept the source field or by removing the source field from the allowlist entries before pushing them to the gateway.

Guidance

  • The issue is caused by a mismatch between the schema expected by the openclaw approvals set --gateway command and the actual schema of the allowlist entries written by the Telegram approval handler.
  • To fix this, you can either modify the gateway schema to accept the source field as an optional string property on allowlist entries or remove the source field from the allowlist entries before pushing them to the gateway.
  • You can verify the fix by checking if the openclaw approvals set --gateway command successfully pushes the allowlist entries to the gateway without rejecting them.
  • As a temporary workaround, you can use a script to strip the source field from the allowlist entries before pushing them to the gateway, as mentioned in the issue description.

Example

# Remove the source field from the allowlist entries before pushing them to the gateway
jq 'del(.source)' ~/.openclaw/exec-approvals.json > temp.json
openclaw approvals set --gateway --file temp.json

Notes

  • The issue affects any install where users tap "Allow always" on Telegram exec approval prompts, and the severity is high because it silently breaks the persistence contract of "Allow always" and causes unbounded drift between the on-disk allowlist and the gateway in-memory state.
  • The workaround of stripping the source field from the allowlist entries before pushing them to the gateway has been in use, but it means the ~/.openclaw/exec-approvals.json file on disk drifts from what actually reaches the gateway.

Recommendation

Apply the workaround of removing the source field from the allowlist entries before pushing them to the gateway, as this is a temporary solution that can be used until the gateway schema is modified to accept the source field.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Either the gateway schema accepts source as an optional string property on allowlist entries (preferred — since Telegram's own approval handler writes it, the schema should describe what's actually on disk), OR the Telegram approval handler stops writing a field the gateway will reject. Whatever the fix, openclaw approvals set (local write) and openclaw approvals set --gateway (gateway push) should agree on the schema — currently the local-write path accepts source without complaint while the gateway path rejects it.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Telegram /approve allow-always writes 'source' field that openclaw approvals set --gateway rejects — allowlist updates silently fail to persist to gateway [3 pull requests]