[BUG] Remote Control epoch-mismatch (409) recovery blocks session exit for ~20s when unrelated concurrent sessions are running

Open 💬 0 comments Opened Jul 2, 2026 by pnutshellmenace

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

  1. 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).
  2. Start a new interactive session with claude --debug-file <path>.
  3. Let it fully load, then run /exit.
  4. 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 recovery error 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.

View original on GitHub ↗