openclaw - ✅(Solved) Fix macOS app/dashboard config writes can drop gateway.auth and restart Gateway [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

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…
GitHub stats
openclaw/openclaw#75631Fetched 2026-05-02 05:32:36
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
2
Author
Timeline (top)
cross-referenced ×2closed ×1commented ×1referenced ×1

The macOS app / dashboard configuration path can rewrite ~/.openclaw/openclaw.json in a way that drops existing gateway auth configuration and triggers a Gateway restart. Active Control UI / dashboard WebSocket clients are then disconnected with 1012 service restart.

This looks related to the existing ConfigStore/AppState conflict work, but the current behavior is still observable on a local macOS setup.

Root Cause

After the rewrite, ~/.openclaw/openclaw.json no longer contained the expected gateway.auth block. The runtime kept working only because the Gateway still had auth/token material available from the environment, but the persisted config had drifted.

Fix Action

Fix / Workaround

  1. Preserve existing gateway.auth and unrelated config fields.
  2. Prefer conflict-aware partial config mutation, e.g. config.patch, instead of full config replacement where possible.
  3. Avoid unnecessary Gateway restarts for Talk/UI settings if hot-reload is enough.
  4. If a restart is required, make it explicit and preserve dashboard/client state cleanly.
  5. Avoid AppState/ConfigStore races when multiple writers touch the same config file.
  • #64973 — very high match: make macOS App ConfigStore/AppState conflict-aware; avoid direct config writes.
  • #4286 — older/high match: App should use config.patch instead of config.set.
  • #20344 — older/high match: App overwrites gateway.auth; closed stale, but the behavior still appears relevant.
  • #43150 / #43244 — Gateway RPC config race / serialization work; helpful, but may not cover direct app file writes.
  • #45507 — token mismatch / restart cascade; related but appears superseded into the AppState/ConfigStore issue.
  • #63753 / #74645 — Talk/TTS routing work; nearby area, but not clearly a fix for this config writer/restart problem.

The robust fix likely needs to make the macOS app/dashboard config writer conflict-aware and patch-based:

PR fix notes

PR #75815: fix(macos): protect gateway auth config writes

Description (problem / solution / changelog)

Summary

Protect the macOS config save path from accidentally clobbering persisted Gateway auth/mode when a Gateway config write is rejected as stale/invalid/auth-related.

This is a focused guard for the App + Dashboard coexistence failure mode: a rejected Gateway write should not silently fall back to a direct full-file write that drops gateway.auth or gateway.mode.

Changes

  • Prevent ConfigStore.save(_:) from falling back to direct local writes after stale/invalid/auth-like Gateway save failures.
  • Harden OpenClawConfigFile.saveDict(_:):
    • preserve existing gateway.auth when a generic direct write omits it
    • reject destructive gateway.mode removal and large suspicious size drops
    • write rejected payloads to .rejected.<timestamp> and audit the rejection
    • return Bool so high-risk call sites can detect rejection
  • Make user-visible direct save call sites notice rejections:
    • AppState.syncGatewayConfigNow() logs and stops on rejected writes
    • DebugSettings.saveSessionStorePath() surfaces a save error
  • Add focused Swift tests for stale Gateway rejection, auth preservation, mode-removal rejection, and AppState auth preservation across mode changes.

Scope / non-scope

  • Addresses #75631, #64973, #74890.
  • Intentional auth removal / full Gateway unconfigure is intentionally out of scope. That should use a future dedicated allow-destructive flow rather than the generic config writer.
  • This does not migrate macOS config saves to config.patch; that remains follow-up work.
  • Gateway RPC error handling is still string-classified on the macOS side because structured Gateway error codes are not currently surfaced there.

Validation

Local validation run from apps/macos:

swift test --filter ConfigStoreTests --filter OpenClawConfigFileTests --filter AppStateRemoteConfigTests

Result:

Test run with 21 tests in 3 suites passed

Also run:

git diff --check

Result: no errors.

Note: the local pre-commit hook could not complete on this host because swiftlint is not installed on PATH; the focused Swift tests above and git diff --check were run manually.

Changed files

  • apps/macos/Sources/OpenClaw/AppState.swift (modified, +6/-1)
  • apps/macos/Sources/OpenClaw/ConfigStore.swift (modified, +32/-1)
  • apps/macos/Sources/OpenClaw/DebugSettings.swift (modified, +4/-1)
  • apps/macos/Sources/OpenClaw/OpenClawConfigFile.swift (modified, +88/-7)
  • apps/macos/Tests/OpenClawIPCTests/AppStateRemoteConfigTests.swift (modified, +34/-0)
  • apps/macos/Tests/OpenClawIPCTests/ConfigStoreTests.swift (modified, +69/-0)
  • apps/macos/Tests/OpenClawIPCTests/OpenClawConfigFileTests.swift (modified, +94/-0)

PR #75953: fix(macos): preserve gateway auth config writes

Description (problem / solution / changelog)

Summary

  • Problem: macOS app/dashboard config writes can fall back to direct full-config saves and drop persisted gateway.auth or unrelated config keys.
  • Why it matters: dropping auth can force restart-time behavior changes and disconnect Control UI/dashboard clients with 1012 service restart.
  • What changed: local fallback saves now merge against a fresh on-disk snapshot, direct saves preserve existing gateway.auth by default, and the Tailscale auth editor opts into explicit auth mutation.
  • What did NOT change (scope boundary): this does not migrate every macOS settings writer to Gateway config.patch or change Gateway RPC semantics.

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 #75631
  • Related #75815
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: macOS app-side full-config fallback writes treated a stale app snapshot as authoritative for the persisted config file.
  • Missing detection / guardrail: direct config saves audited suspicious changes but did not preserve gateway.auth before writing.
  • Contributing context (if known): Gateway config.set/config.patch paths have stronger base-hash protections than the local macOS fallback path.

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: apps/macos/Tests/OpenClawIPCTests/OpenClawConfigFileTests.swift
  • Scenario the test should lock in: direct and fallback-style config writes preserve existing gateway.auth and unrelated config keys unless the caller explicitly edits auth.
  • Why this is the smallest reliable guardrail: it exercises the macOS file writer and merge behavior without requiring a live Gateway restart.
  • Existing test that already covers this (if any): N/A
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

macOS/dashboard settings writes preserve persisted Gateway auth and unrelated config by default, reducing surprise disconnect/auth drift after settings changes.

Diagram (if applicable)

Before:
[dashboard/app setting save] -> [local full-config fallback] -> [gateway.auth may disappear]

After:
[dashboard/app setting save] -> [fresh snapshot merge] -> [gateway.auth and unknown keys preserved]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) Yes
  • 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: this hardens persisted token/auth handling by preserving existing gateway.auth unless a caller explicitly opts into auth mutation.

Repro + Verification

Environment

  • OS: macOS host, SwiftPM package under apps/macos
  • Runtime/container: local checkout on Node 24.13.0 / pnpm workspace
  • Model/provider: N/A
  • Integration/channel (if any): macOS app/dashboard config path
  • Relevant config (redacted): tests use temp OPENCLAW_STATE_DIR and OPENCLAW_CONFIG_PATH

Steps

  1. Start with an openclaw.json containing gateway.auth and unrelated config.
  2. Save a partial macOS app/dashboard config snapshot that omits auth and unrelated keys.
  3. Reload the config from disk.

Expected

  • Existing gateway.auth is still present.
  • Unrelated config keys are still present for fallback-merge writes.
  • Explicit auth edits can still remove or replace auth by opting into auth mutation.

Actual

  • Matches expected after this patch.

Evidence

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

Human Verification (required)

What I personally verified (not just CI), and how:

  • Verified scenarios:
    • swift test --package-path apps/macos --filter OpenClawIPCTests.OpenClawConfigFileTests
    • swift test --package-path apps/macos --filter OpenClawIPCTests.ConfigStoreTests
    • node scripts/check-changed.mjs CHANGELOG.md apps/macos/Sources/OpenClaw/ConfigStore.swift apps/macos/Sources/OpenClaw/OpenClawConfigFile.swift apps/macos/Sources/OpenClaw/TailscaleIntegrationSection.swift apps/macos/Tests/OpenClawIPCTests/OpenClawConfigFileTests.swift
    • git diff --check origin/main..HEAD
  • Edge cases checked: explicit auth mutation remains possible through the Tailscale auth editor path; fallback merge preserves unrelated nested config.
  • What you did not verify: a live macOS dashboard settings gesture 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: N/A

Risks and Mitigations

  • Risk: some caller intentionally expected a generic direct save to remove gateway.auth by omission.
    • Mitigation: callers that edit auth can pass allowGatewayAuthMutation: true; the known auth editor path does so.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • apps/macos/Sources/OpenClaw/ConfigStore.swift (modified, +8/-2)
  • apps/macos/Sources/OpenClaw/OpenClawConfigFile.swift (modified, +65/-4)
  • apps/macos/Sources/OpenClaw/TailscaleIntegrationSection.swift (modified, +1/-1)
  • apps/macos/Tests/OpenClawIPCTests/OpenClawConfigFileTests.swift (modified, +104/-0)

Code Example

code=1012 reason=service restart
RAW_BUFFERClick to expand / collapse

Summary

The macOS app / dashboard configuration path can rewrite ~/.openclaw/openclaw.json in a way that drops existing gateway auth configuration and triggers a Gateway restart. Active Control UI / dashboard WebSocket clients are then disconnected with 1012 service restart.

This looks related to the existing ConfigStore/AppState conflict work, but the current behavior is still observable on a local macOS setup.

Environment

  • OpenClaw: 2026.4.27 (cbc2ba0)
  • Host: macOS / Darwin 25.4.0, arm64, Mac mini
  • Runtime: Gateway already running and reachable
  • Attach-only marker present: ~/.openclaw/disable-launchagent
  • Config path: ~/.openclaw/openclaw.json
  • Logs checked:
    • ~/.openclaw/logs/gateway.log
    • ~/.openclaw/logs/gateway.err.log
    • ~/.openclaw/logs/config-audit.jsonl

What happened

While testing the macOS app / dashboard Talk configuration path, WebSocket RPCs such as:

  • config.set
  • voicewake.set

caused the Gateway to restart/reload. The dashboard connection was dropped with:

code=1012 reason=service restart

After the rewrite, ~/.openclaw/openclaw.json no longer contained the expected gateway.auth block. The runtime kept working only because the Gateway still had auth/token material available from the environment, but the persisted config had drifted.

Expected behavior

The macOS app / dashboard should not directly rewrite the full persisted config in a way that can drop existing keys.

Expected safer behavior:

  1. Preserve existing gateway.auth and unrelated config fields.
  2. Prefer conflict-aware partial config mutation, e.g. config.patch, instead of full config replacement where possible.
  3. Avoid unnecessary Gateway restarts for Talk/UI settings if hot-reload is enough.
  4. If a restart is required, make it explicit and preserve dashboard/client state cleanly.
  5. Avoid AppState/ConfigStore races when multiple writers touch the same config file.

Actual behavior

  • A Talk/dashboard settings write rewrote the persisted config.
  • Existing auth-related config disappeared from openclaw.json.
  • Gateway restarted/reloaded.
  • Dashboard WebSocket disconnected with 1012 service restart.
  • The system appeared to keep working only because runtime env auth still existed, not because the config was intact.

Why this is risky

This creates a brittle split-brain state:

  • persisted config says one thing,
  • runtime env says another,
  • the app/dashboard can trigger restarts while writing settings,
  • and a later clean start may behave differently from the current running process.

For users relying on Gateway auth, this can look like a random dashboard disconnect or auth/config regression after touching voice/Talk settings.

Related issues / PRs noticed

These look related, but I could not confirm that the concrete macOS app direct-config-write path is fixed:

  • #64973 — very high match: make macOS App ConfigStore/AppState conflict-aware; avoid direct config writes.
  • #4286 — older/high match: App should use config.patch instead of config.set.
  • #20344 — older/high match: App overwrites gateway.auth; closed stale, but the behavior still appears relevant.
  • #43150 / #43244 — Gateway RPC config race / serialization work; helpful, but may not cover direct app file writes.
  • #45507 — token mismatch / restart cascade; related but appears superseded into the AppState/ConfigStore issue.
  • #63753 / #74645 — Talk/TTS routing work; nearby area, but not clearly a fix for this config writer/restart problem.

Suggested fix direction

The robust fix likely needs to make the macOS app/dashboard config writer conflict-aware and patch-based:

  • Do not treat the app's current state snapshot as authoritative full config.
  • Never write a partial in-memory app state over the whole persisted config.
  • Preserve unknown/unowned keys by default.
  • Serialize or reconcile writes against Gateway-side config changes.
  • Add regression coverage for preserving gateway.auth while changing Talk/dashboard settings.

Minimal regression test idea

  1. Start with an openclaw.json containing gateway.auth plus unrelated user config.
  2. Trigger a macOS app/dashboard Talk setting write, e.g. voicewake.set or equivalent UI action.
  3. Assert that:
    • gateway.auth remains present and unchanged,
    • unrelated config fields remain present,
    • no unnecessary Gateway restart occurs unless explicitly required,
    • dashboard WebSocket clients are not dropped for a simple settings write.

Notes

I have intentionally not included tokens, full config contents, or secret-bearing log output here.

extent analysis

TL;DR

The macOS app/dashboard configuration path should be modified to use a conflict-aware, patch-based approach to update the ~/.openclaw/openclaw.json file, preserving existing gateway.auth and unrelated config fields.

Guidance

  • Review the related issues (#64973, #4286, #20344) to understand the existing work on conflict-aware config writes and patch-based updates.
  • Implement a patch-based approach for the macOS app/dashboard config writer, preserving unknown/unowned keys by default.
  • Add regression coverage for preserving gateway.auth while changing Talk/dashboard settings, using a test similar to the suggested minimal regression test idea.
  • Consider serializing or reconciling writes against Gateway-side config changes to avoid config drift.

Example

No specific code example is provided, as the issue requires a high-level design change to the config writer.

Notes

The suggested fix direction requires careful consideration of the existing config store and app state conflicts, as well as the potential impact on Gateway restarts and dashboard WebSocket clients.

Recommendation

Apply a workaround by modifying the macOS app/dashboard configuration path to use a conflict-aware, patch-based approach, as this will help prevent the loss of existing gateway.auth configuration and reduce the likelihood of unnecessary Gateway restarts.

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

The macOS app / dashboard should not directly rewrite the full persisted config in a way that can drop existing keys.

Expected safer behavior:

  1. Preserve existing gateway.auth and unrelated config fields.
  2. Prefer conflict-aware partial config mutation, e.g. config.patch, instead of full config replacement where possible.
  3. Avoid unnecessary Gateway restarts for Talk/UI settings if hot-reload is enough.
  4. If a restart is required, make it explicit and preserve dashboard/client state cleanly.
  5. Avoid AppState/ConfigStore races when multiple writers touch the same config file.

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 macOS app/dashboard config writes can drop gateway.auth and restart Gateway [2 pull requests, 1 comments, 2 participants]