[BUG] Desktop Remote Control: the bridge auto-creates and claims its single session slot at startup; Code-tab sessions never register and hang at "Connecting"

Status Fixed / completed
Reported on v2.1.229
Maintainer reply None cached
Activity 1 comment · opened Aug 14, 2026 · closed Aug 25, 2026

Preflight Checklist

  • [x] I have searched existing issues. Closest matches are #84502, #85086 and #84994, but those describe Desktop sessions that never register. This is the opposite: registration succeeds and the session is reachable on mobile — delivery is what fails. Filing separately; cross-referenced below.
  • [x] This is a single bug report
  • [x] I am using the latest version

What's Wrong?

The Desktop app's session bridge persists exactly one remoteSessionId per account in %APPDATA%\Claude\bridge-state.json. Once that binding goes stale, it is reconnected on every app launch and holds the single bridge slot indefinitely. Every subsequently remote-enabled session then mints a valid claude.ai/code/session_... URL, logs bridge_state: connected, and appears on mobile — but the environment never receives work for it. The phone sits at "Connecting…" forever, with no error, no timeout, and no way to recover from the UI.

Critically: restarting the app does not clear it. The stale binding is re-established on each launch. Recovery requires hand-editing bridge-state.json.

Environment

  • Claude Desktop 1.30096.1.0, Windows 11 Pro 26200, MSIX (Claude_pzs8sxrjxfjjc)
  • Bundled Claude Code 2.1.229, CLAUDE_CODE_ENTRYPOINT=claude-desktop
  • claude.ai OAuth, personal account
  • Mobile: Claude iOS app, Code tab

Expected

Enabling remote control on a session binds that session to the bridge environment, and messages sent from mobile are delivered to it. If a slot is genuinely single-occupancy, the app should say so and offer to release the old binding — not silently hang.

Actual

The newly enabled session is minted and never touched again. Across a 4.5 MB main.log, the new session id appears exactly once:

10:44:22 [info] [remote-control] bridge_state: ready
10:44:22 [info] Remote control enabled: https://claude.ai/code/session_01Chv…
10:44:22 [info] [remote-control] bridge_state: connected

No Poll received work. No Connecting transport. No Received user message. Note bridge_state: connected is reported while the session is not in fact attached — the local side reports success it cannot know.

Every inbound message — all 18 — went to a different, three-day-old session instead:

$ grep -oE "Received user message for session cse_[A-Za-z0-9]+" main.log | sort | uniq -c
     18 Received user message for session cse_01Qgh…

That session (a Cowork session from three days prior) is the one persisted in bridge-state.json, and it is re-adopted on every launch:

10:25:04 [info] [sessions-bridge] Reconnecting persisted session cse_01Qgh…
10:25:07 [info] [sessions-bridge] Connecting transport for session cse_01Qgh…
10:33:37 [info] [sessions-bridge] Session cse_01Qgh… turn completed, keeping transport open for follow-ups

The binding survived four app restarts (Aug 12 17:45, Aug 13 07:22, Aug 13 23:11, Aug 14 08:16, Aug 14 10:25) — each one reconnected the same stale session.

Two secondary defects visible in the same logs

1. Phantom in-flight turns. The bridge repeatedly finds turn counters for the stale session that do not correspond to real work, resets them, and deliberately keeps the transport open:

10:30:20 [warn] Stale pendingTurns detected for session cse_01Qgh… (pendingTurns=5), resetting counter and keeping transport open
10:43:01 [warn] Stale pendingTurns detected for session cse_01Qgh… (pendingTurns=2), resetting counter and keeping transport open

2. Ack queue never drains. pendingProcessedAcks accumulates and is never emptied:

"processedMessageUuids": [ …15 entries… ],
"pendingProcessedAcks":  [ …7 entries… ]

Acking 4 pending processed events fires on reconnect, but the queue still had 7 outstanding afterwards.

Historical pattern (this is not a one-off)

The bound session only ever changes when the state file changes. On Aug 8, six sessions were remote-enabled; only the one in bridge-state.json ever received traffic:

Remote control enabled: session_013h49…   never polled
Remote control enabled: session_01Gcb…   never polled
Remote control enabled: session_01BVF…   never polled
Remote control enabled: session_01JBR…   never polled
Remote control enabled: session_01CEo…   never polled
Remote control enabled: session_015pj…   never polled

Bound session over time: cse_01Fge…cse_015Ek…cse_01Qgh…. One at a time, always the persisted one.

This is aggravated by remote control auto-enabling on every new session ([rcAutoEnable] verdict: enable=true source=explicit_pref), so each new session silently competes for a slot it cannot win.

Reproduction

  1. Enable remote control on a session; drive it from mobile. It works.
  2. Abandon that session without disabling remote control. Restart the Desktop app.
  3. Open a new session, enable remote control, open its claude.ai/code/… link on mobile.
  4. Send a message. It hangs at "Connecting" indefinitely. Restarting does not help.

Workaround

Quit Desktop, then in %APPDATA%\Claude\bridge-state.json set remoteSessionId and localSessionId to null and empty processedMessageUuids / pendingProcessedAcks, keeping enabled, userConsented and environmentId so consent is not re-prompted. Clear replBridgePlaceholders in ~/.claude.json. Relaunch.

Suggested fixes

  • Don't report bridge_state: connected until the environment has actually acknowledged work for that session id.
  • Surface a real error on the mobile client when no environment is attached, instead of an unbounded "Connecting" spinner.
  • Release or expire the persisted binding when its session is no longer live, rather than re-adopting it across restarts.
  • If the slot is single-occupancy by design, say so in the UI and offer to hand the slot over.
  • Drain pendingProcessedAcks, and treat repeated Stale pendingTurns as a signal to tear the transport down rather than hold it open.

Note on identifiers

Session, environment, org and account IDs are truncated above. Full values can be provided privately if it helps server-side correlation.

Possibly related

#84502, #85086, #84994 — those report Desktop sessions never registering. The single-slot binding described here may be an alternative presentation of the same underlying constraint, where the observable differs depending on which session holds the slot.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗