[BUG] remoteControlAtStartup races OAuth token refresh at cold start → transient 401 'Remote credentials fetch failed' (--rc flag is clean)

Status Fixed / completed
Maintainer reply None cached
Activity 1 comment · opened Jul 17, 2026 · closed Aug 5, 2026

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, subscription max, no ANTHROPIC_API_KEY in env
  • claude auth status: loggedIn: true; daemon shows a valid token (auth: scheduling proactive refresh in 10887s)
  • No DISABLE_TELEMETRY / CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC set (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

  1. settings.json: "remoteControlAtStartup": true; claude.ai OAuth, no ANTHROPIC_API_KEY.
  2. Cold-start (after the access token has gone stale — e.g. first launch after idle): claude --debug.
  3. Observe status bar: Remote credentials fetch failed — see debug log.
  4. grep -E 'remote-bridge|code-session|401' ~/.claude/debug/<session>.txt → the 401 sequence above.
  5. Compare: claude --rc --debug (or remoteControlAtStartup: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. 🤖

View original on GitHub ↗

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