Skip to content

fix(controller): stop masquerading gateway WS failure as credential failure - #1128

Merged
alchemistklk merged 2 commits into
mainfrom
fix/channel-status-masquerade
Apr 15, 2026
Merged

fix(controller): stop masquerading gateway WS failure as credential failure#1128
alchemistklk merged 2 commits into
mainfrom
fix/channel-status-masquerade

Conversation

@alchemistklk

Copy link
Copy Markdown
Contributor

What

Fix the controller's getAllChannelsLiveStatus fallback paths so a transient OpenClaw gateway WebSocket failure no longer looks like a credential failure in the UI. Channels now report status: "connecting", configured: true (rendering as an amber spinner) instead of status: "disconnected", configured: false (rendering as a red shield with a "Reconnect required" CTA).

Why

Closes #856.

After 0.1.10-nightly.20260406 users reported every IM channel showing as disconnected with a re-auth prompt, despite their tokens on disk being valid. Nothing was actually reset — only the live-status reply was lying. When the controller's WS to OpenClaw was unreachable (multiple gateway-reload loops landed in that nightly: skillhub sync churn, key-reorder reloads, langfuse restart, OAuth apiKey: "" rejection), both fallback branches in openclaw-gateway-service.ts returned every channel as status: "disconnected" / configured: false, which the web UI is wired to treat as a credential failure.

The Apr 10–14 fixes (7a03c2b0, 87ea4cb9, 02e73549, bf631409) stabilized the gateway so this stopped firing in practice, but the masquerade is still latent on main — any future WS flap would reproduce #856 exactly. This PR removes the latent bug and makes the failure mode honest.

How

  • apps/controller/src/services/openclaw-gateway-service.ts: both the WS-not-connected pre-check branch and the RPC-throws catch branch now return status: "connecting", configured: true, lastError: null, gatewayConnected: false. The existing "connecting" UI path (home.tsx:273-327 getChannelStatusMeta) already renders the correct amber spinner without a re-auth CTA, and the existing top-level "Offline" pill (driven by /api/internal/desktop/ready) + "Agent starting…" pill (driven by agent.alive) already communicate the gateway-unavailable state. No new banner / i18n strings were needed.
  • Service constructor loses its now-unused runtimeState / isBootPhasePreReady threading; container.ts and two test fixtures updated.
  • Two new vitest cases for the WS-not-connected and RPC-throws branches.
  • Full investigation + verification write-up at specs/design-docs/2026-04-15-channel-status-masquerade-fix.md, including a sidebar on launchd supervision behaviour (OpenClaw auto-restarts within ~5s of a crash — verified live).

Smoke-tested in a packaged unsigned macOS arm64 build: killed OpenClaw with launchctl bootout + kill -9, UI correctly showed red "Offline" + amber "Agent starting…" + amber Feishu "Connecting…" with no re-auth prompt; restored OpenClaw, everything returned to green within one poll cycle, no re-auth required.

Affected areas

  • Desktop app (Electron shell)
  • Controller (backend / API)
  • Web dashboard (React UI)
  • OpenClaw runtime
  • Skills
  • Shared schemas / packages
  • Build / CI / Tooling

Checklist

  • pnpm typecheck passes
  • pnpm lint passes (0 errors from this change; pre-existing unused-var warning in skillhub-custom-import.test.ts unrelated)
  • pnpm test passes for touched areas (controller suite: 255 passing, 24 pre-existing failures on origin/main unchanged)
  • pnpm generate-types run (if API routes/schemas changed) — not needed, schema unchanged

…credential failure

Issue #856: after 0.1.10-nightly.20260406 users reported all IM channels
showing as disconnected with a "Reconnect required" CTA, forcing them to
re-authenticate channels whose tokens on disk were still valid.

Root cause: openclaw-gateway-service.ts#getAllChannelsLiveStatus had two
fallback paths (WS-not-connected pre-check and RPC-throws catch) that
both returned status:"disconnected", configured:false, lastError:null
for every channel. The web UI treats that shape as a real credential
failure and prompts re-auth. When the OpenClaw gateway WS was
transiently unreachable (skillhub sync churn, deterministic-config
reload, langfuse restart, OAuth apiKey rejection) every channel got
flagged disconnected despite nothing being wrong.

Channel records on disk were never touched — only the live-status reply
lied.

Fix: both fallback paths now return status:"connecting", configured:true,
lastError:null. The existing UI path for "connecting" (home.tsx:273-327
getChannelStatusMeta) already renders the amber spinner without a
re-auth CTA, and the existing "Offline" + "Agent starting…" header pills
already communicate the gateway-unavailable state. No new banner or
i18n strings were needed.

Supporting cleanup: runtimeState / isBootPhasePreReady threading was
only used by the branch we just simplified, so the service constructor
drops that parameter. container.ts and the two test fixtures
(openclaw-gateway-service.test.ts, route-compat.test.ts) updated for the
new signature.

Tests: two new cases in openclaw-gateway-service.test.ts cover the
WS-not-connected and RPC-throws branches and assert the honest shape.

Packaged smoke test (macOS arm64, unsigned): baseline green, kill
openclaw via launchctl bootout + kill -9, UI flips to red Offline / amber
Agent-starting / amber Feishu-connecting with NO red shield and NO
Reconnect CTA; restart openclaw, UI returns to green within one poll
cycle with no re-auth required. Full write-up at
specs/design-docs/2026-04-15-channel-status-masquerade-fix.md including
a sidebar on launchd KeepAlive supervision (OpenClaw auto-restarts
within ~5s of a crash as long as the controller is alive).
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 15, 2026

Copy link
Copy Markdown

Deploying nexu-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 570362b
Status: ✅  Deploy successful!
Preview URL: https://c2e1d8f0.nexu-docs.pages.dev
Branch Preview URL: https://fix-channel-status-masquerad.nexu-docs.pages.dev

View logs

@sentry

sentry Bot commented Apr 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ontroller/src/services/openclaw-gateway-service.ts 0.00% 5 Missing ⚠️
apps/controller/src/app/container.ts 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@alchemistklk
alchemistklk merged commit 4c9bd2d into main Apr 15, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] All channel connection states are reset in version 0.1.10-nightly.20260406

2 participants