Summary
The macOS OpenClaw.app dashboard fails to load, showing "Dashboard unavailable / Could not connect to the server", with the connect URL containing a literal double-URL-encoded, unresolved config placeholder instead of the actual gateway token:
http://127.0.0.1:18789/#token=$%257BOPENCLAW_GATEWAY_TOKEN%257D
Decoding twice: %257B → %7B → {, giving ${OPENCLAW_GATEWAY_TOKEN} — the literal ${VAR} placeholder string from openclaw.json, not the resolved secret value.
Environment
- OpenClaw 2026.6.11 (gateway + CLI, pnpm/npm-global installs)
- macOS OpenClaw.app (native menu-bar/dashboard app), same version
- Gateway running via a per-user LaunchAgent (launchd), local mode (
ws://127.0.0.1:18789)
gateway.auth.token in openclaw.json is stored as a template reference: "${OPENCLAW_GATEWAY_TOKEN}", with the actual secret value in a .env file consumed by the gateway's LaunchAgent EnvironmentVariables / service-env file.
Steps to reproduce
- Configure
gateway.auth.token in openclaw.json as "${OPENCLAW_GATEWAY_TOKEN}", with the real token supplied only via the gateway service's own environment (e.g. LaunchAgent EnvironmentVariables, not the global user/session environment).
- Launch OpenClaw.app from the Dock/Finder (i.e., not from a shell that has
OPENCLAW_GATEWAY_TOKEN exported).
- Open the dashboard from the app.
Expected behavior
Either:
- The app should ask the running gateway for its dashboard URL (with token already resolved server-side), rather than resolving
${OPENCLAW_GATEWAY_TOKEN} itself from its own process environment; or
- If the app must resolve the token client-side, it should read it from the same source the gateway process uses (e.g. shared service-env file) rather than only the ambient GUI-launchd environment; or
- At minimum, if the token placeholder cannot be resolved, the app should show a clear, actionable error (e.g. "Gateway token is not configured/resolvable from this app; open Settings to set it manually") instead of silently passing the literal
${VAR} string into the connect URL.
Actual behavior
- The app resolves the token from its own process environment only.
- macOS GUI apps launched via Dock/Finder do not inherit env vars that are scoped only to a separate per-service LaunchAgent (a well-known macOS launchd behavior, not an OpenClaw bug in itself) — so
OPENCLAW_GATEWAY_TOKEN is typically absent from the app's environment even though the gateway process has it.
- When resolution fails, the app does not fall back or surface a clear error. It substitutes the literal unresolved string
${OPENCLAW_GATEWAY_TOKEN}, URL-encodes it (apparently twice), and uses it as the #token= fragment when opening the dashboard URL.
- Result: dashboard permanently shows "Could not connect to the server", and because the dashboard itself fails to load, the in-app Settings screen used to manually re-enter the token is also unreachable — there is no way to recover from within the app UI.
- Re-entering the token via Settings when reachable, or fully quitting/relaunching the app, does not durably fix this, because the underlying env-resolution gap is still present on next launch (or after any process working-directory/environment reset).
Impact
- Complete lockout from the dashboard/Settings UI in this configuration, with no in-app recovery path.
- Silent failure mode (unresolved placeholder passed through) makes the actual cause (env var not visible to the app) very hard to diagnose from the UI alone; it required inspecting the running gateway's logs/auth-rate-limit state and then binary-searching the app bundle's strings/config-loading logic to find the real cause.
Suggested fixes (any one would resolve this)
- Prefer fetching the effective/resolved dashboard URL (with token) from the gateway's own API/IPC channel, rather than templating the URL from local config + local env.
- If client-side resolution of
${ENV_VAR} placeholders is required, document (or auto-detect) that the referenced env var must be present in the broader user/login environment (e.g. via launchctl setenv), not only inside a specific LaunchAgent's environment block — and ideally read from the same resolved service-env file the gateway itself uses.
- Add explicit error handling: if a
${...} placeholder in gateway.auth.token cannot be resolved to a real value, do not proceed to construct/open a dashboard URL with the raw placeholder. Show an explicit "token not resolvable" error with a path to fix it (env var name expected, and/or an option to enter a literal token override in Settings) — and ensure this error path itself does not depend on the dashboard already having loaded.
Notes
- This is a config/UX robustness issue in the app's env-driven token resolution and error handling, not a report of a specific typo in any one user's config — the underlying scenario (secret sourced from a LaunchAgent-scoped env var, app launched via Dock/Finder without that env var visible) is a common and expected macOS deployment pattern for this kind of app.
Summary
The macOS OpenClaw.app dashboard fails to load, showing "Dashboard unavailable / Could not connect to the server", with the connect URL containing a literal double-URL-encoded, unresolved config placeholder instead of the actual gateway token:
Decoding twice:
%257B→%7B→{, giving${OPENCLAW_GATEWAY_TOKEN}— the literal${VAR}placeholder string fromopenclaw.json, not the resolved secret value.Environment
ws://127.0.0.1:18789)gateway.auth.tokeninopenclaw.jsonis stored as a template reference:"${OPENCLAW_GATEWAY_TOKEN}", with the actual secret value in a.envfile consumed by the gateway's LaunchAgentEnvironmentVariables/ service-env file.Steps to reproduce
gateway.auth.tokeninopenclaw.jsonas"${OPENCLAW_GATEWAY_TOKEN}", with the real token supplied only via the gateway service's own environment (e.g. LaunchAgentEnvironmentVariables, not the global user/session environment).OPENCLAW_GATEWAY_TOKENexported).Expected behavior
Either:
${OPENCLAW_GATEWAY_TOKEN}itself from its own process environment; or${VAR}string into the connect URL.Actual behavior
OPENCLAW_GATEWAY_TOKENis typically absent from the app's environment even though the gateway process has it.${OPENCLAW_GATEWAY_TOKEN}, URL-encodes it (apparently twice), and uses it as the#token=fragment when opening the dashboard URL.Impact
Suggested fixes (any one would resolve this)
${ENV_VAR}placeholders is required, document (or auto-detect) that the referenced env var must be present in the broader user/login environment (e.g. vialaunchctl setenv), not only inside a specific LaunchAgent's environment block — and ideally read from the same resolved service-env file the gateway itself uses.${...}placeholder ingateway.auth.tokencannot be resolved to a real value, do not proceed to construct/open a dashboard URL with the raw placeholder. Show an explicit "token not resolvable" error with a path to fix it (env var name expected, and/or an option to enter a literal token override in Settings) — and ensure this error path itself does not depend on the dashboard already having loaded.Notes