[BUG] VS Code 60s init timeout fires on a VALID token with successful authenticated API calls — the error message blames auth and network, both provably fine (corroborates #80004)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
New VS Code session cold start Anthropic Claude Code extension fails to log in using my Pro plan with OAuth.
What Should Happen?
Bug report — VS Code extension: the 60s init watchdog kills a healthy, authenticated subprocess and reports it as an auth/network failure
Reporter: Nicholas Stein (bizcadsystems.com) · Filed from: Windows 11 Pro build 26300
Observed: 2026-08-06 09:19 PDT and 2026-08-07 07:39 PDT (UTC-7) · Reproduces: first launch of most working days
---
Summary
Opening VS Code shows a login error in the CLAUDE CODE chat panel. Clicking new session
succeeds. The user worked around this silently for days before investigating.
We captured the failure twice, and the two occurrences have different underlying causes but
produce the identical symptom and the identical message:
| | 2026-08-06 | 2026-08-07 |
|---|---|---|
| OAuth token at spawn | expired ~11h | valid, 6h40m remaining |
| CLI's startup API calls | three 401s in 250ms | all 200 — Fetch ok, Fetched 3 servers |
| Extension auto-update in flight | yes — 2.1.223 installed 2s before | yes — 2.1.224 installed 3s before |
| launch_claude → actual spawn | 15.8s | 11.7s |
| Init handshake | never sent | never sent |
| Killed at | spawn +60.007s | spawn +60.010s |
| CLI process after the kill | alive, logging [skills] idle | alive, logging [skills] idle |
| Message shown | "…check authentication and network connectivity" | "…check authentication and network connectivity" |
⛔ The 2026-08-07 occurrence is the important one. The subprocess made two successful
authenticated calls to api.anthropic.com 58 seconds before it was killed, and was still
running healthily 1.5s after. Authentication was fine. The network was fine. The message the
user is shown is not merely unhelpful — it is false, and it names the only two subsystems that
were demonstrably working.
The underlying defect is that initialization can stall without erroring, and nothing reports
what it stalled on. The expired token (08-06) is one way in. There is at least one other.
What we would like fixed, in priority order
- Stop attributing the timeout to auth/network. The subprocess should report *what it was
waiting on* when the watchdog fires. As written, the message actively misdirects: it cost this
reporter roughly two days of investigation, most of it aimed at the wrong subsystem, and it
pointed us at a local SessionStart hook that we then had to spend real effort exonerating
(twice — see §Excluded).
- Surface the stall. Between
[mcp-registry] Loaded 294 official MCP URLs(07:39:23.008) and
the kill (07:40:20.759) there are 42 seconds of complete log silence at DEBUG level, from a
process that is alive and polling. Whatever init awaits, it is not instrumented.
- Validate token expiry before spawning, not just presence. The extension logs
OAuth tokens found in secure storage — presence, not validity — and spawns anyway.
expiresAt is in the credential record. This addresses the 08-06 path.
- Refresh in-band on a startup 401, or fail fast with an actionable error, rather than
stalling until the watchdog fires.
- Investigate the extension-update interaction (§Leading hypothesis). Both captured failures
happened seconds after an in-place extension update, with an anomalous 12–16s delay before the
subprocess spawned.
Leading hypothesis: the failure happens during an in-place extension auto-update
We did not expect this and we are not certain of it, but it is now 2 for 2 with a mechanism and
a measurable signature:
| | 2026-08-06 | 2026-08-07 |
|---|---|---|
| New version unpacked | 2.1.223 at 09:19:02–06 | 2.1.224 at 07:39:02.349 – 07:39:06.024 |
| extensions.json rewritten | 09:19:06 | 07:39:06.343 |
| Extension host activates | 09:19:04.810 | 07:39:07.622 |
| launch_claude requested | 09:19:04.810 | 07:39:09.047 |
| Subprocess actually spawned | 09:19:20.631 (+15.8s) | 07:39:20.749 (+11.7s) |
| Binary spawned | …2.1.222…\claude.exe | …2.1.223…\claude.exe |
| New version on disk at that moment | 2.1.223 | 2.1.224 |
In both cases the panel spawned the superseded binary while a newer version had just landed on
disk, and in both cases the spawn was delayed by an order of magnitude more than a warm launch.
A healthy launch on this machine reports time_to_interactive: 3745ms.
This also explains, without any auth involvement, why "new session" always fixes it: by the
time the user clicks it, the update has settled.
It does not explain every occurrence — the recurrence data (evidence 03) shows the
first-session signature on days with no extension update, and on those days the expired token
does explain it. We think there are two distinct triggers converging on one un-instrumented stall.
A hypothesis we are explicitly demoting
The last CLI line before the 42s silence on 08-07 is [mcp-registry] Loaded 294 official MCP URLs. This reporter has three claude.ai connectors (Gmail, Calendar, Drive) that are
(legacy)
unauthorized on this machine, and the CLI logs [MCP] claude.ai connectors running fully async at 07:39:21.907. That made MCP an attractive suspect. We are reporting it because
(nonblocking)
you may see something in it that we cannot, but "last line before the silence" is weak evidence
— it is simply where logging stops when nothing else logs. The update correlation above is
stronger and we would look there first.
Relationship to existing reports — this is corroboration, not a new sighting
We searched before filing. This error has a substantial open cluster, and we are not claiming a
novel defect; we are contributing the best-instrumented instance we could capture.
| Issue | Overlap |
|---|---|
| #80004 — "Extension host becomes unresponsive during Claude Code startup … consistent 60s timeout despite subprocess initializing normally" | ⭐ Closest match. Independently reports the same core observation: full CLI init in ~2s, then "total silence until the 60s timeout fires", with claude -p proving auth and network are fine. Had 0 comments when we looked |
| #77680 | "…always times out (60s) — TCP/TLS/proxy all confirmed working externally" — same "the blamed subsystems are fine" conclusion |
| #72315 | The exact error string, VS Code |
| #50559 | "…on Windows — regression from 2.1.114" |
| #69769 (closed) | 60s timeout traced to permissions.allow rules referencing unmounted drives on Windows — a permission/config path into the same stall |
What we add that those do not have:
- A timestamped log of a successful, authenticated API round-trip 58 seconds before the kill —
#80004 infers auth is fine from a separate claude -p run; we have it from the *stalled
subprocess itself*.
- Two captures with different underlying causes (expired token / valid token) producing the
identical message, which shows the message is not diagnostic of anything.
- The extension auto-update correlation, 2 for 2, with the 12–16s pre-spawn delay.
One of #80004's signatures does NOT reproduce here. They seeExtension host (LocalProcess pid: …) is unresponsive in VS Code's own DevTools/main log during
the window. We searched Code\logs\20260807T073853\main.log for that signature across our failure
window and found zero hits — our extension host stayed responsive. So either there are two
distinct paths into this stall, or extension-host unresponsiveness is a symptom rather than the
cause. We report the negative result because it is the kind of thing that otherwise gets assumed.
Incidental finding: workspace trust never sticks, because the same folder has three keys
Not the cause of the timeout, but found while investigating it and probably worth a separate look.~\.claude.json holds three separate project entries for one directory, differing only in
drive-letter case and path separator:
| key | hasTrustDialogAccepted |
|---|---|
| G:\repos\AI\RoadTrip | true |
| G:/repos/AI/RoadTrip | true |
| g:/repos/AI/RoadTrip | false ← the one actually consulted |
The 08-07 log shows the consequence directly:
[DEBUG] Dropped 6 project-scoped permissions.allow entries — workspace not yet trusted
Ignoring 6 permissions.allow entries … Run Claude Code interactively here once and accept the
trust dialog, or set projects["g:/repos/AI/RoadTrip"].hasTrustDialogAccepted: true
The user has accepted the trust dialog — twice, evidently — but the accepted state was written
under a differently-cased key than the one read at startup, so it never takes effect and six
permission entries are silently dropped on every launch. Windows paths are case-insensitive;
these keys should be canonicalized. Given #69769 (permission rules → 60s timeout), a permission
set that is silently different from what the user configured seems worth ruling in or out here too.
Environment
| | 2026-08-06 | 2026-08-07 |
|---|---|---|
| VS Code | 1.132.0 | 1.132.0 (df53daabb18cd157bdb08c7f01c34df936cf12f4, x64) |
| Extension host version | 2.1.222 | 2.1.223 |
| Version installed seconds earlier | 2.1.223 | 2.1.224 |
| CLI spawned (extension-bundled) | 2.1.222 | 2.1.223 |
| OS | Windows 11 Pro build 26300 | same |
| Auth | claude.ai, firstParty, subscription pro | same |
| Timezone | PDT (UTC-7) | same |
<h1>This report corroborates https://github.com/anthropics/claude-code/issues/80004 and provides additional evidence</h1>
*Corroborates #80004 and #77680. Filing separately because this capture includes a successful
authenticated API round-trip from the stalled subprocess itself, plus a second capture with a
different root cause and the same message.*
⭐ The failure is version-independent: observed on extension host 2.1.222 and 2.1.223. The
2026-08-06 report's open question — "is this also present on 2.1.223?" — is now answered: yes.
Standalone CLI 2.1.211 exists at ~/.local/bin/claude.exe on PATH; the panel does not use it.
Account identifiers "Happy to provide account identifiers and the untruncated log privately for server-side correlation — say the word.":
- email
[redacted](removed for public filing)]` - orgId
[redacted](removed for public filing) - the three 401s of 08-06 occurred at 2026-08-06T16:19:31Z, within ~250ms of each other.
- on 08-07 there are no 401s to correlate — the calls at 2026-08-07T14:39:22Z succeeded.
Timeline — 2026-08-07 (the valid-token failure)
Source: evidence 06, %APPDATA%\Code\logs\20260807T073853\window1\exthost\Anthropic.claude-code\Claude VSCode.log
| Local | UTC | Event |
|---|---|---|
| 06:20:49 | 13:20:49 | Scheduled pre-warm task runs, LastTaskResult 0 |
| 06:20:58 | 13:20:58 | .credentials.json rewritten; new expiresAt = 14:20:58 |
| 07:38:53 | 14:38:53 | VS Code starts (log session 20260807T073853) |
| 07:39:02–06 | 14:39:02 | Extension 2.1.224 unpacked; extensions.json rewritten 07:39:06.343 |
| 07:39:07.622 | 14:39:07 | Extension activates; OAuth tokens found in secure storage |
| 07:39:09.047 | 14:39:09 | launch_claude, channel khweia9fxf, cwd g:\repos\AI\RoadTrip |
| 07:39:20.749 | 14:39:20 | Subprocess spawned, version: 2.1.223 (+11.7s) — watchdog t0 |
| 07:39:21.9 | 14:39:21 | hook_execution_start (the reporter's SessionStart hook) |
| 07:39:21.907 | 14:39:21 | [MCP] claude.ai connectors running fully async (nonblocking) |
| 07:39:22.541 | 14:39:22 | ✅ [claudeai-mcp] Fetched 3 servers — authenticated call, 200 |
| 07:39:22.576 | 14:39:22 | Org fast mode: disabled (extra_usage_disabled) — no 401 |
| 07:39:22.662 | 14:39:22 | ✅ [Bootstrap] Fetch ok — second authenticated call, 200 |
| 07:39:23.008 | 14:39:23 | [mcp-registry] Loaded 294 official MCP URLs (legacy) — last CLI output |
| — | — | 42 seconds of complete silence |
| 07:40:05.778 | 14:40:05 | User submits a prompt into the stalled panel |
| 07:40:20.759 | 14:40:20 | Closing Claude on channel khweia9fxf |
| 07:40:20.760 | 14:40:20 | ❌ Subprocess initialization did not complete within 60000ms — check authentication and network connectivity — spawn +60.010s |
| 07:40:22.332 | 14:40:22 | 🔴 Orphaned CLI logs [skills] idle — switching poll interval to 30000ms — it never crashed; it was alive and healthy after being killed |
Timeline — 2026-08-06 (the expired-token failure)
Source: evidence 01, line numbers cited.
| Local | UTC | Event | Line |
|---|---|---|---|
| 09:18:57 | 16:18:57 | Extension host starts (ide/41255.lock created) | — |
| 09:19:02–06 | 16:19:02 | Extension 2.1.223 unpacked/installed | — |
| 09:19:04.810 | 16:19:04 | Extension activates; OAuth tokens found in secure storage; launch_claude | 5, 20 |
| 09:19:20.631 | 16:19:20 | Subprocess spawned, version: 2.1.222 (+15.8s) | 22 |
| 09:19:21 | 16:19:21 | CLI init proceeds normally — CA certs, settings, skills, MCP configs | 23–147 |
| — | 16:19:31.154 | [Bootstrap] Fetch failed: 401 / fetchBootstrapData failed: AxiosError 401 | 190, 192 |
| — | 16:19:31.172 | [claudeai-mcp] Fetch failed (401) after 1 attempt(s) | 194 |
| — | 16:19:31.402 | Failed to fetch org fast mode status … 401 | 196 |
| — | — | 49 seconds of complete silence | — |
| 09:20:20.638 | 16:20:20 | …did not complete within 60000ms — spawn +60.007s | 199 |
| 09:20:21.966 | 16:20:21 | Orphaned CLI logs [skills] idle — stalled, not crashed | 209 |
| 09:25:50 | 16:25:50 | User clicks new session | 214–216 |
| 09:25:53.5 | 16:25:53 | [claudeai-mcp] Fetched 3 servers; same calls now 200 | 463, 465 |
| 09:25:53 | 16:25:53 | .credentials.json rewritten; new expiresAt = 17:25:53 (= +8h exactly) | fs |
| 09:25:53.891 | 16:25:53 | time_to_interactive: 3745ms | 507 |
Why we concluded the 08-06 token was expired
- TTL is 8h: refreshed 09:25:53,
expiresAt17:25:53. Independently reconfirmed on 08-07
(refresh 06:20:58 → expiresAt 14:20:58).
- Last CLI activity before the failure was 2026-08-05 ~14:32, so with an 8h TTL the token in
play expired ~11h before the 09:19 launch. (The issue time is bounded by observed activity
timestamps, not separately recorded.)
- No credential write during the failed run.
.credentials.jsonmtime was 09:25:53 — the
second the retry succeeded. The failing run never refreshed.
- Three independent endpoints 401'd within 250ms — that points at the credential, not a service.
None of this reasoning applies to 08-07, where the credential was written at 06:20:58 by a
scheduled pre-warm and the same three endpoints returned 200.
Alternative causes tested and excluded
Please don't spend time on these — we already did.
- "The user's
SessionStarthook hung." Rejected on both days. Its append-only witness
(evidence 03) shows the body running to completion in ~1s on 08-07 (all three lines stamped
07:39:24) and ~3s on 08-06. Its configured timeout is 30s, which cannot produce a 60s stall.
Both the hook script and the refresh it triggers use detached Start-Process and never -Wait.
- "The hook's detached grandchild inherits the stdio pipe, so the harness never sees EOF" —
the classic Windows hang. Rejected by controlled experiment (evidence 05): read-to-EOF returned
in 1.5s with both streams piped and the hook process exited cleanly.
- "Expired token" — excluded for 08-07 by three independent measurements: the pre-warm task's
exit code, the credential file mtime and expiresAt, and two successful authenticated API
calls made by the subprocess itself.
- "Network" — excluded for 08-07 by the same two successful calls to
api.anthropic.com,
58 seconds before the kill.
⚠️ Note for your diagnosis: the CLI logs Hook … success only after the network stage. On
08-06 the 401s swallowed that line entirely, which makes the hook look guilty in the log when it
is not. That log ordering is worth revisiting on its own — it is what sent us down the wrong path.
Recurrence
Evidence 03 shows the same first-session-of-day signature on 08-03, 08-04, 08-05, 08-06 and
08-07: a cold session, then a second one 4–10 minutes later. Extension updates occurred on three
of those five days.
Additional finding: there is no supported way to pre-warm the credential
While building a local mitigation we measured that nothing refreshes a token pre-emptively.
Against a live token, neither claude auth status --json nor a real claude -p "ok" inference
call advances expiresAt (evidence 04). Refresh happens only at or after expiry.
Against a genuinely expired token (08-07 06:20, evidence 04) the behaviour splits:
[2026-08-07 06:20:54] token EXPIRED (expires 2026-08-07 01:24:33) [via ext 2.1.223]
[2026-08-07 06:20:56] -> 'auth status' did NOT refresh (expiry unchanged)
[2026-08-07 06:21:01] -> REFRESHED by 'claude -p' (new expiry 2026-08-07 14:20:58)
⭐ claude auth status does not refresh an expired token; only a real inference call does.
That is worth knowing on its own — auth status is the command a user would reach for.
Combined with defect #3, this means the only thing that refreshes an expired token is a session,
and the first session of the day is precisely the one that fails. Our workaround is a logon-time
scheduled task that runs claude -p; it works (the expiry advances), and it did not prevent the
2026-08-07 failure — which is how we found that the timeout has a second cause.
Evidence index
| File | What it is | Why it matters |
|---|---|---|
| 01-extension-output-channel.log | Output → Claude Code channel, 08-06 09:19–09:26, both runs | The 401s, the 60s timeout, the successful retry |
| (02 withdrawn) | Reporter's session log | Removed before filing for redaction reasons; its content is told directly in this document |
| 03-sessionstart-hook-witness.log | Append-only hook witness | Exonerates the hook on both days; shows the 5-day recurrence |
| 04-token-prewarm-witness.log | Local mitigation's log | The lazy-refresh measurement and the auth status vs claude -p split |
| 05-hook-pipe-exclusion-test.ps1 | Reproduction script | Re-run the pipe-inheritance exclusion |
| 06-extension-log-20260807.log | Extension log for the 08-07 failure, truncated to the failure window (07:39:07 → 07:40:22, 220 lines) | ⭐ The primary artifact — valid token, 200s, 42s silence, kill at +60.010s, [skills] idle after. Trimmed at the retry boundary; happy to supply more of it on request |
Redaction statement
.credentials.json is deliberately excluded; only expiry metadata is quoted anywhere in this
package. Evidence 01 and 06 contain permissions.allow arrays enumerating the reporter's local
project tooling and paths; they are diagnostically irrelevant and may be stripped on request.
Verified 2026-08-07, not merely asserted. Scanned evidence 01 and 06 for unredacted
credential-shaped strings (sk-ant, gho_/ghp_, Twilio SIDs, DSNs with inline passwords):
zero hits in each, against 2 and 48 [REDACTED] markers respectively — Claude Code redacted
them before writing the log, and the claim now rests on a measurement rather than on trust.
Two artifacts were withdrawn or trimmed, and we would rather state why than quietly ship them:
- Evidence 02 (the reporter's session log) has been removed from the package. It was
redaction-reviewed at 10,818 bytes and had grown to 940,891 bytes — 87× — after that review,
with 37 lines matching credential-shaped patterns. Its only job was narrative, which this
document now carries directly.
- Evidence 06 is truncated to the failure window (07:39:07 → 07:40:22, 220 lines, 30 KB). The
full file is a live log of the reporter's working session: scanned clean at 384,837 bytes, it was
469,166 bytes twenty minutes later, the new bytes being a base64 screenshot pasted into chat.
Nothing was removed from within the failure window; the cut is at the first line of the
unrelated retry session. The untruncated log is available on request.
The general principle we applied: a redaction review is only valid for the bytes that were
reviewed, and two of these artifacts were still being written to. refresh_evidence.ps1 now
enforces both decisions with fail-closed guards so they cannot silently unwind.
Error Messages/Logs
Opening VS Code shows a login error in the CLAUDE CODE chat panel. Clicking **new session**
succeeds. The user worked around this silently for days before investigating.
Steps to Reproduce
Open VS by double-clicking the code-workspace file
See body and evidence package for my workflow, logs and test script
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
unknown
Claude Code Version
2.1.211 (Claude Code)
Platform
Other
Operating System
Windows
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗