[BUG] Remote Control epoch-mismatch (409) recovery blocks session exit for ~20s when unrelated concurrent sessions are running
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet — related but distinct: #67934 documents the same
Epoch mismatch (409)error triggered by two clients attaching to the same live session (causing a fork); this report is about the recovery being slow (~20s) when the trigger is unrelated concurrent sessions, not simultaneous attach to one session. - [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
When a Remote-Control-enabled session's CCR (Claude Code Remote) epoch gets superseded (409) — apparently due to contention with other, unrelated Claude Code sessions running concurrently under the same account, not from anyone attaching to the same session — the client doesn't detect and recover from this quickly. Instead it takes roughly 20 seconds for the conflict to surface, and normal UI actions (in my case, /exit) appear to hang for that entire window before the client notices the epoch mismatch and proceeds with shutdown.
Once the mismatch is detected, recovery itself is fast (session archive + teardown completes in under a second). The delay is entirely in getting to that detection — the client appears to be waiting on its normal presence-pulse/heartbeat interval rather than reacting promptly to the 409.
Steps to Reproduce
- Have Remote Control enabled (
remoteControlAtStartup: true, the default) with multiple Claude Code sessions/processes already running concurrently under the same account (e.g. a couple of interactive sessions, a background daemon, an agents process). - Start a new interactive session with
claude --debug-file <path>. - Let it fully load, then run
/exit. - Observe: the CLI appears to hang for ~15–20 seconds before actually exiting, with no visible feedback that anything is happening.
Forensic Evidence
Timestamps relative to process start, from a --debug-file capture (session/account identifiers redacted):
t= 1.15s [remote-bridge] Created session <session-id>
t= 1.28s [presence] wired for session <session-id>
t= 1.49s CCRClient: initialized, epoch=1
t= 1.49s [remote-bridge] v2 transport connected
t= 4.68s [presence] pulse → https://api.anthropic.com/v1/code/sessions/<session-id>/client/presence
t= 10.05s [presence] pulse → https://api.anthropic.com/v1/code/sessions/<session-id>/client/presence
t= 17.37s [presence] terminal focus → blurred <- /exit typed around here
t= 22.14s CCRClient: Heartbeat sent <- 4.8s after focus change
t= 26.55s [ERROR] CCRClient: Epoch mismatch (409), shutting down
t= 26.55s [bridge:repl] CCR v2: epoch superseded (409) — closing for poll-loop recovery
t= 26.55s [WARN] CCRClient: client events failed: epoch superseded
t= 26.57s [remote-bridge] Archive session <session-id> status=200
t= 26.87s [remote-bridge] Torn down (archive=200)
t= 26.94s SessionEnd hooks begin running (complete in <100ms)
Roughly 9.5 seconds elapse between the terminal losing focus and the next heartbeat firing, and a further 4.4 seconds between that heartbeat and the 409 being surfaced — all before the exit sequence is even allowed to start. Total exit latency: ~26.9s from process start to actual shutdown, of which the actual shutdown work (hooks + MCP teardown + archive) is well under 1s.
Expected Behavior
- A superseded epoch should be detected and surfaced promptly (sub-second, or at minimum not gated behind a multi-second heartbeat/pulse interval), so it doesn't block unrelated UI actions like
/exit. - Ideally, an epoch conflict from unrelated concurrent sessions shouldn't block or delay local session shutdown at all — Remote Control bridge teardown should be able to proceed independently of whether the bridge handshake is in a clean or conflicted state.
Environment
- Claude Code: interactive CLI 2.1.198
- OS: macOS 26.5.2 (build 25F84), Apple Silicon
- Setup: several Claude Code processes running concurrently under one account at the time of the repro (a couple of interactive sessions, one background daemon process, one agents process) — no SSH or mobile/Desktop dual-attach involved
remoteControlAtStartup: true (default) at time of repro
Related
- #67934 — same
Epoch mismatch (409)/closing for poll-loop recoveryerror signature, but describes session forking from dual-client attach (Desktop + mobile) to one live session, with no mention of shutdown latency. Possible the two reports share a root cause in the CCR v2 poll-loop/epoch reconciliation logic, but the reproduction and user-visible symptom differ enough that a fix scoped to "don't fork on dual-attach" might not address this latency issue.