[BUG] Remote Control fails at bridge init: /v1/code/sessions intermittently 401s a valid OAuth token (~50-70% of requests, split backend fleet)
Summary
Interactive --remote-control shows the × Remote Control Failed banner at session start. Root cause (reproduced outside the CLI): api.anthropic.com/v1/code/sessions intermittently returns 401 "Authentication failed" for a valid OAuth token — identical back-to-back requests alternate between 200 and 401, which looks like a split backend fleet (rolling deploy or bad subset of instances). The CLI only retries 3 times, so with ~50% per-request failure the bridge init frequently loses all three and gives up.
Re-running /login does not help (and can't — see evidence below).
Environment
- Claude Code v2.1.212, Windows 10 (10.0.19045)
- Claude Max (personal), OAuth login, scopes include
user:sessions:claude_code - First observed 2026-07-17 ~10:36 UTC; a session launched at 10:34 UTC connected fine, sessions launched from 10:36 onward fail
Debug log (from claude --remote-control <name> --debug)
Before re-login (session create passes on retry, /bridge credentials fetch fails 3/3):
10:44:29 [code-session] Session create failed 401: Authentication failed
10:44:29 [remote-bridge] createCodeSession failed (attempt 1/3), retrying in 412ms
10:44:30 [remote-bridge] Created session cse_01Gw7625bCM136xwhmzuicXA
10:44:31 [code-session] /bridge failed 401: Authentication failed
10:44:31 [remote-bridge] fetchRemoteCredentials failed (attempt 1/3), retrying in 594ms
10:44:31 [code-session] /bridge failed 401: Authentication failed
10:44:32 [code-session] /bridge failed 401: Authentication failed
10:44:32 [remote-bridge] Creds failed; onStateChange set, msg="Remote credentials fetch failed — see debug log"
10:44:32 [bridge:repl] handleStateChange state=failed detail="Remote credentials fetch failed — see debug log"
After a fresh /login (10:53 UTC) — same failure, now at session create:
10:54:46 [code-session] Session create failed 401: Authentication failed
10:54:46 [remote-bridge] createCodeSession failed (attempt 1/3), retrying in 385ms
10:54:46 [code-session] Session create failed 401: Authentication failed
10:54:48 [code-session] Session create failed 401: Authentication failed
10:54:48 [bridge:repl] handleStateChange state=failed detail="Session creation failed — see debug log"
Evidence the token is valid and the failure is server-side
All of the following used the freshly-minted accessToken from ~/.claude/.credentials.json (expiry valid, subscriptionType: max):
GET api.anthropic.com/api/oauth/profile→ 200 every time.- Normal CLI inference on the same token works throughout (the session doing this debugging runs on it).
GET api.anthropic.com/v1/code/sessions?limit=1withanthropic-version: 2023-06-01, 8 identical requests over ~10 seconds:
````
200 401 200 200 401 200 401 401
- Even the 401s are inconsistent with each other: without the
anthropic-versionheader, responses alternate between 401authentication_errorand 400"anthropic-version: header is required"— i.e. some backends pass auth and fail on header validation, others reject the same token at the auth layer. Paired examples seconds apart, same token:
req_011Cd7WjLcxvngbdyqBxigQa→ 401 Authentication failedreq_011Cd7WjPrg3XJtPg9TvLxpZ→ 400 missing anthropic-version (auth passed)
- The 401 responses still include the resolved
anthropic-organization-idresponse header, so the token is being recognized before rejection. - Worker-mode
claude remote-control(which registers via/v1/environments/bridgeinstead) connected instantly on the same credentials — only the/v1/code/sessionsservice is affected.
Expected
Consistent auth decisions for the same valid token; and/or a bridge init that survives a transiently-flaky backend (3 rapid retries is too few when the failure mode is per-request roulette — a longer/backoff retry like the post-connect reconnect path already has would have masked this entirely).
Actual
~50% of requests to /v1/code/sessions 401; bridge init exhausts its 3 attempts and Remote Control permanently shows the Failed banner for that session.
🤖 Generated with Claude Code
6 Comments
Two follow-ups after another hour of debugging:
1. Failure is sustained and per-request (not connection-sticky). ~50 min after first report, the 401 rate is holding or worse (8/12, then 6/10 identical requests). It is not tied to connection reuse or HTTP version — on a single keep-alive connection I got
200then five401s; fresh HTTP/1.1 connections and Node'sfetch(the CLI's stack) show the same roulette. So retrying inside one process doesn't dodge a "bad backend" — every request is an independent coin flip.2. The real UX problem: a failed initial connect permanently disables Remote Control for that session. From the bundled code, when bridge init returns null the client runs
replBridgeEnabled: falseand never retries — unlike the post-connect drop path, which patiently reconnects with backoff for up to 10 minutes. With today's ~50-65% per-request failure rate compounding across the several sequential authenticated calls init makes, most fresh sessions land in the permanently-failed state. For users running many parallel sessions that means manually toggling/remote-controlin every window, repeatedly, until each one wins the coin flip.Request: give the initial connect the same background retry/backoff loop the reconnect path already has. That one change would have made this server incident a non-event (sessions would self-heal when the fleet recovers) instead of a hard outage requiring per-session manual intervention.
🤖 Generated with Claude Code
Corroborating from macOS (also v2.1.212, Max, claude.ai OAuth): I filed #78470 with the same signature minutes after this issue, before finding it. Extra data points consistent with the split-fleet read: (1) within a single process and a single in-memory token,
/bridgewent 401, 401, success across 1.6s (10:54:07-08 UTC) and then connected normally; (2) in a run where/bridgefailed 3/3, the same token archived the just-createdcse_session with status 200 one second later; (3) onset on my side was ~10:07 UTC, and status.claude.com showed Degraded Performance for api.anthropic.com, claude.ai, and Claude Code from 06:47 UTC. Also seconded that worker-modeclaude remote-controlconnected fine throughout, so only the/v1/code/sessionspath is affected.Status update: the endpoint has degraded from intermittent to fully down. Automated monitoring (5 probes every ~2 min, same valid token) has returned 0/5 successes for 10 consecutive rounds (~20+ minutes of 100% 401s on /v1/code/sessions, while /api/oauth/profile continues to return 200). Remote Control is now hard-down for this account rather than a retry-luck problem.
Recovery: as of ~14:09 UTC the endpoint is healthy again (5/5 monitored probes returning 200) and a real --remote-control bridge init now completes (one 401 still occurred on the first createCodeSession attempt but the retry succeeded; credentials fetch and transport connect were clean). Total observed impact for this account: ~3.5 hours of Remote Control being unusable. The design-gap request stands: a background retry on failed init would have made this self-healing.
Recurrence data point: the code-session endpoints degraded again for this account roughly an hour after the ~14:09 UTC recovery reported above.
Environment: Claude Code v2.1.212, macOS (Darwin 25.5.0) arm64, Max subscription, claude.ai OAuth. Access token freshly refreshed at 14:50 UTC (verified via keychain expiry metadata), so token staleness is excluded.
Timeline (2026-07-17 UTC) — same machine, same account, same token:
| time | action | result |
|---|---|---|
| 15:05:27 | manual
/remote-controlin an existing interactive session | ✅ connected || 15:06:10 | new interactive session launched with
--remote-control(flag verified attached viaps) | ❌ "Remote Control failed" banner at startup || 15:07:39 | fresh diagnostic launch,
--remote-control --debug-file| ❌ log below || 15:08:52 | manual
/remote-controlin the 15:06 session | ✅ connected |Launch-time init went 0/2 while manual
/remote-controlwent 2/2 inside the same 3.5-minute window. That matches the per-request 401 roulette + 3-attempt budget described in this issue, amplified by the permanent give-up after a failed init (manual/remote-controlbeing the only retry path in the process).Debug log from the 15:07:39 failure — eligibility check passed, session create passed,
/bridgelost all three attempts:Two details consistent with earlier observations here: the same process archived the just-created session with
status=200one second after/bridge401'd 3/3, and normal inference + MCP traffic on the same token worked throughout — only the code-session path is affected.status.claude.com was still showing Degraded Performance for api.anthropic.com / Claude Code at the time (incident last updated 14:57 UTC), so this may simply be the same incident continuing past the partial recovery — but it does mean the outage window is longer/waves rather than a single resolved blip.
Seconding the design-gap feedback above: a background retry (or any retry path after init failure that doesn't require a human typing
/remote-control) would have made every one of these launch failures self-healing.**Additional data point: the "gives up forever" retry policy turns an intermittent 401 into a multi-day silent outage for unattended sessions**
Environment: Claude Code on Linux (Synology DSM 7, x86_64),
claude --remote-control <name>running 24/7 as an unattended daemon under cron + tmux, Claude Max OAuth.Same root cause as reported here (intermittent 401 on the bridge-init endpoints). What I'd like to add is the operational consequence of the retry policy when nobody is watching the terminal:
Claude Maxbanner, non-zero ESTABLISHED connections (MCP/telemetry keep the pool warm), no restart loop, no non-zero exit.Remote Control failedtext rendered in the TUI pane. We now scrape the tmux pane for it and recycle the session on first sight (kill + relaunch with--continue). That works because the 401 is intermittent — a fresh process is just a new dice roll — but it's a workaround for a client-side retry gap, not a fix.Suggestions, in order of preference:
Happy to provide
--debuglogs from the Linux side if that's useful.