[BUG] remoteControlAtStartup races OAuth token refresh at cold start → transient 401 'Remote credentials fetch failed' (--rc flag is clean)
Summary
With "remoteControlAtStartup": true in settings.json, a cold-start session shows Remote Control failed · Remote credentials fetch failed — see debug log in the status bar. Debug logs show the remote-bridge fires its first API calls (POST /v1/code/sessions and /bridge) before the OAuth access token is refreshed, so those calls return HTTP 401 Authentication failed. Backoff-retry usually recovers once the token refreshes a few seconds later, but the UI has already painted the error; when the retries exhaust before the refresh lands, it stays red.
Launching the same account, same machine, seconds apart via the --rc / --remote-control flag (or in-session /rc) is clean — zero 401s — because that path defers bridge init until after session/auth initialization, when the token is already fresh.
This is the same stale-OAuth-token → credential-fetch-401 mechanism hypothesised in #78597, but a different trigger: #78597 is the in-session slash command in a long-lived session; this is the cold-start remoteControlAtStartup auto-enable path.
Environment
- Claude Code v2.1.212 (latest), native install
- macOS Darwin 25.5.0 (Apple Silicon)
- Auth: claude.ai OAuth,
firstParty, subscriptionmax, noANTHROPIC_API_KEYin env claude auth status:loggedIn: true; daemon shows a valid token (auth: scheduling proactive refresh in 10887s)- No
DISABLE_TELEMETRY/CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICset (ruled out)
Evidence (A/B, captured on the same machine minutes apart with --debug)
A — remoteControlAtStartup: true auto-path (session 8cb20a86…): three 401s, then recovers
17:26:33.852 [code-session] Session create failed 401: Authentication failed
17:26:33.852 [remote-bridge] createCodeSession failed (attempt 1/3), retrying in 380ms
17:26:34.325 [code-session] Session create failed 401: Authentication failed
17:26:34.325 [remote-bridge] createCodeSession failed (attempt 2/3), retrying in 1015ms
17:26:35.546 [remote-bridge] Created session cse_01NYsbQTKex2EWGoVCFuHRoW ← attempt 3 ok
17:26:36.110 [code-session] /bridge failed 401: Authentication failed
17:26:36.111 [remote-bridge] fetchRemoteCredentials failed (attempt 1/3), retrying in 602ms
17:26:36.867 [remote-bridge] Fetched bridge credentials (expires_in=28800s) ← recovered
17:26:37.057 [remote-bridge] v2 transport connected
The status bar surfaces the first fetchRemoteCredentials 401 as "Remote credentials fetch failed" even though the bridge connects ~3.5 s later.
B — --rc flag path (session 79222d57…), remoteControlAtStartup: false: zero 401s
17:28:17.240 [remote-bridge] Created session cse_01AqUkamtAFjZK3sSjhrpB1u ← first try
17:28:17.703 [remote-bridge] Fetched bridge credentials (expires_in=28800s) ← first try
17:28:17.704 [remote-bridge] v2 session URL: https://api.anthropic.com/v1/code/sessions/cse_01AqUkamtAFjZK3sSjhrpB1u
17:28:17.874 [remote-bridge] v2 transport connected
Same auth, same box; the only difference is when bridge init runs relative to token refresh. In path A the bridge fires during the early "background startup prefetches" phase (before the token is refreshed); in path B it fires after session/auth init.
Root cause
Startup ordering. remoteControlAtStartup schedules the remote-bridge createCodeSession / fetchRemoteCredentials calls during cold-start background prefetch, ahead of the OAuth access-token refresh, so the first 1–2 requests carry a stale token → 401. The --rc flag and in-session /rc don't, because they run after auth is initialized.
Steps to Reproduce
settings.json:"remoteControlAtStartup": true; claude.ai OAuth, noANTHROPIC_API_KEY.- Cold-start (after the access token has gone stale — e.g. first launch after idle):
claude --debug. - Observe status bar:
Remote credentials fetch failed — see debug log. grep -E 'remote-bridge|code-session|401' ~/.claude/debug/<session>.txt→ the 401 sequence above.- Compare:
claude --rc --debug(orremoteControlAtStartup:false+ manual/rc) → no 401.
Note: it is a race, so it reproduces reliably only when the token is stale at launch; when the token was freshly refreshed, the auto-path connects without 401.
Impact / expected behavior
The bridge should not issue its first credentialed request until the OAuth token is guaranteed fresh (await/trigger the refresh, or treat a startup 401 as "retry after refresh" without surfacing a user-visible failure). Today the auto-startup path is strictly worse than --rc for the same outcome.
Secondary: "see debug log" is only useful with --debug
The 401 detail is written to ~/.claude/debug/<session>.txt only when the session is launched with --debug. A normal user hitting this gets a status bar that says "see debug log" with no corresponding log written — same gap reported in #78380.
Workaround
Disable the setting and inject the flag at launch (a shell wrapper that adds --rc to interactive launches connects cleanly every time).
---
Filed with debug evidence captured via Claude Code. 🤖
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗