Skip to content

[Bug]: Control UI webchat flashes credentials gate on tab re-focus due to immediate connected=false render #72500

Description

@brandco

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Every time the browser tab loses and regains focus, the webchat briefly flashes the full credentials/login gate before reconnecting and restoring the normal chat UI. On fast connections this lasts ~300–800ms; on slower connections (Pi-class hardware) it is more visible.

Steps to reproduce

  1. Open the Control UI webchat with an authenticated session
  2. Switch to another app or browser tab for any duration
  3. Switch back to the Control UI tab
  4. Observe the credentials gate (WebSocket URL + token + password fields) flash briefly before the chat UI appears

Expected behavior

Switching back to a previously authenticated tab should show a brief "reconnecting..." indicator overlaid on the existing chat content, or no transition at all if reconnection is fast. The full credentials gate should only appear when the user has never connected or when auth explicitly fails (401/403).

Actual behavior

The credentials gate appears on every reconnect cycle because `app-render.ts` renders `renderLoginGate()` unconditionally whenever `state.connected === false`:

```typescript
// app-render.ts:666
if (!state.connected) {
return html`${renderLoginGate(state)} ${renderGatewayUrlConfirmation(state)}`;
}
```

And `app-gateway.ts` sets `connected = false` immediately on any WebSocket close — including expected transient browser-initiated closes when the tab goes to background — with no debounce or "reconnecting" intermediate state:

```typescript
// app-gateway.ts:266 — set at start of every connectGateway() call
host.connected = false;

// app-gateway.ts:347 — set in onClose handler
host.connected = false; // immediately triggers full re-render to credentials gate
```

There is no distinction between "never authenticated" and "temporarily disconnected from a known-good session." Both states render the same credentials gate.

Root cause

The app has two render states — connected (show chat) or not connected (show credentials gate) — with no intermediate "reconnecting" state. Browser tab visibility changes trigger WebSocket closes, which set `connected = false`, which immediately re-renders the full credentials gate. A debounce of even 1–2 seconds on the `connected = false` transition would eliminate the flash for normal tab switches.

Suggested fix

  1. Add a third `reconnecting` state distinct from `disconnected` (never auth'd or auth failed)
  2. Only show the full credentials gate when: (a) no prior successful connection exists in this session, or (b) the server explicitly returns 401/403
  3. For transient disconnects from a known-good session, show a non-blocking "reconnecting..." banner over existing chat content
  4. Debounce the `connected = false` render trigger by ~1–2 seconds to absorb brief interruptions

OpenClaw version

2026.4.24 (cbcfdf6)

Operating system

Raspberry Pi 5 (Linux 6.12 arm64) — also reproducible on any OS with the webchat UI

Install method

npm global

Screenshot

The attached screenshot shows the credentials gate that appears during the flash (captured from a fresh headless session to demonstrate the state):

Before (bug state — what appears during flash): Full credentials form with WebSocket URL, token, and password fields
Expected after (not shown): Normal chat interface restored without credentials interruption

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions