openclaw - 💡(How to fix) Fix 401 Unauthorized on control-ui-config.json after any config change via Control UI [1 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#84356Fetched 2026-05-20 03:41:13
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
1
Author
Timeline (top)
labeled ×2closed ×1commented ×1

Error Message

GET http://127.0.0.1:18789/__openclaw/control-ui-config.json 401 (Unauthorized) The FetchEvent for "http://127.0.0.1:18789/chat?..." resulted in a network error response sw.js: Uncaught (in promise) TypeError: Failed to convert value to 'Response'

Root Cause

When openclaw.json is rewritten, the runtime config snapshot refreshes via setRuntimeConfigSnapshot(), but the gateway's resolvedAuth used by authorizeControlUiReadRequest() is evaluated through getResolvedAuth()resolveGatewayAuth() which reads from getActiveSecretsRuntimeSnapshot()?.config.gateway?.auth.

The secrets runtime snapshot (activeSnapshot) is only refreshed during explicit activateSecretsRuntimeSnapshotState() calls. After a config write, finalizeRuntimeSnapshotWrite() updates the config snapshot but does not trigger a corresponding secrets snapshot refresh when only the config file changed (no auth store reload). The result: resolvedAuth resolves stale auth state while the Control UI sends its current device token. The auth check fails with 401.

The service worker crash is secondary — fetch() rejects when the gateway closes the connection during the auth failure, and event.respondWith() receives a rejected promise instead of a Response.

Fix Action

Fix / Workaround

Workarounds

Code Example

GET http://127.0.0.1:18789/__openclaw/control-ui-config.json 401 (Unauthorized)
The FetchEvent for "http://127.0.0.1:18789/chat?..." resulted in a network error response
sw.js: Uncaught (in promise) TypeError: Failed to convert value to 'Response'
RAW_BUFFERClick to expand / collapse

Bug Description

Every time I change config through the Control UI settings panel, the UI immediately breaks with 401 Unauthorized on /__openclaw/control-ui-config.json. A full page hard-refresh (Ctrl+Shift+R) or killing and restarting the gateway fixes it until the next change.

Environment

  • OpenClaw version: 2026.5.18
  • Gateway mode: local
  • Auth mode: token
  • Bind: loopback (127.0.0.1:18789)
  • OS: Linux (CachyOS)

Steps to Reproduce

  1. Open Control UI at http://127.0.0.1:18789
  2. Change any config value (e.g. toggle a setting, change model alias)
  3. Save
  4. Observe 401 on control-ui-config.json and broken UI

Browser Console Output

GET http://127.0.0.1:18789/__openclaw/control-ui-config.json 401 (Unauthorized)
The FetchEvent for "http://127.0.0.1:18789/chat?..." resulted in a network error response
sw.js: Uncaught (in promise) TypeError: Failed to convert value to 'Response'

Root Cause Analysis

When openclaw.json is rewritten, the runtime config snapshot refreshes via setRuntimeConfigSnapshot(), but the gateway's resolvedAuth used by authorizeControlUiReadRequest() is evaluated through getResolvedAuth()resolveGatewayAuth() which reads from getActiveSecretsRuntimeSnapshot()?.config.gateway?.auth.

The secrets runtime snapshot (activeSnapshot) is only refreshed during explicit activateSecretsRuntimeSnapshotState() calls. After a config write, finalizeRuntimeSnapshotWrite() updates the config snapshot but does not trigger a corresponding secrets snapshot refresh when only the config file changed (no auth store reload). The result: resolvedAuth resolves stale auth state while the Control UI sends its current device token. The auth check fails with 401.

The service worker crash is secondary — fetch() rejects when the gateway closes the connection during the auth failure, and event.respondWith() receives a rejected promise instead of a Response.

Workarounds

  • Hard refresh (Ctrl+Shift+R) usually recovers
  • Kill + restart gateway fully fixes until next config change
  • Changing config via CLI (openclaw config set ...) does not trigger this bug

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING