[BUG] Claude Code 60s Timeout

Status Open
Reported on v2.1.114
Maintainer reply ✓ Yes — bcherny
Activity 4 comments · opened Jul 28, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

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?

At extension startup / on model set, the Claude Code extension fails with:

Failed to set model: Error: Subprocess initialization did not complete within 60000ms - check authentication and network connectivity

The "authentication and network connectivity" text is misleading. Neither is the cause. The extension spawns a separate config-probe subprocess (spawnConfigProbe()) alongside the real session subprocess. The probe finishes its work in under a second (hooks, MCP, startup all complete), but its initializationResult() acknowledgment never reaches the extension, so the extension waits the full 60s and then errors. This matches the mechanism identified in #60045: the probe loses an IPC race to the real session subprocess and never acks. It is an extension-side probe/transport problem, not the binary, auth, or network.

Corroborating existing reports: #50559 (2.1.114/115), #50988 (2.1.114), #51541 (2.1.116), #60342 (2.1.143), #64168, #69769, #54230 all describe the same timeout; most were closed as duplicate / not-planned / stale without a fix, and repeatedly note the CLI, the integrated terminal, and the desktop app all work while only the extension's spawned subprocess hangs. This is a regression from an earlier working version.

Environment:

  • OS: Windows 11 Pro 10.0.26200
  • Editor: Cursor (VS Code fork) running the Claude Code extension
  • Extension version: 2.1.220
  • Shell: Git Bash (MINGW64)
  • Auth: Claude OAuth

Machine-side causes ruled out (so this is not the reporter's setup):

  • Not the settings drive-path issue (#69769): ~/.claude/settings.json, ~/.claude.json, and the project .claude/settings.json contain no additionalDirectories and no slow/unmounted drive-letter or POSIX drive paths.
  • Not a slow shell snapshot: a login + interactive shell (bash -l -i -c exit) starts in about 0.5s; no .bashrc / .bash_profile / .profile present.
  • Not auth: credentials are valid and present (logs show tokens found in secure storage immediately before the timeout, as in #60342 / #50988).
  • Not network: connectivity is fine; the CLI and other paths work.

What Should Happen?

The extension should initialize in well under a second (as the CLI and the real session subprocess already do) and set the model without waiting on the config probe. Per #60045's suggestions, any of:

  • Load config lazily from the first real session instead of blocking startup on a separate probe.
  • Reuse the first real session's config instead of spawning a separate probe process.
  • Remove or greatly increase the probe timeout, and treat a probe that completed-but-did-not-ack as success rather than a fatal session failure.
  • At minimum, stop presenting a completed-but-unacked probe as an "authentication and network connectivity" error, which sends every reporter down the wrong diagnostic path.

Error Messages/Logs

Error: Subprocess initialization did not complete within 60000ms — check authentication and network connectivity

Steps to Reproduce

Context needed to reproduce: native Windows (not WSL), the Claude Code extension running in VS Code or Cursor, valid credentials present, and a config with no additionalDirectories and no slow-drive paths (a clean default config still reproduces it, which is the point: it is not config-dependent).

  1. On Windows, open the workspace in VS Code or Cursor with the Claude Code extension installed.
  2. Start a Claude Code session (or trigger a model set) so the extension spawns its startup subprocess(es).
  3. Observe: the extension shows "Subprocess initialization did not complete within 60000ms - check authentication and network connectivity" after exactly ~60 seconds.

Confirm it is the probe, not the binary/auth/network (each of these succeeds while the extension times out):

  1. CLI works directly:

``
claude -p ping
`
returns
pong`.

  1. Manual stream-json handshake completes instantly from a terminal (from #64168):

``
echo '{"type":"control_request","request_id":"t1","request":{"subtype":"initialize"}}' | claude --input-format stream-json --output-format stream-json --verbose --model sonnet --permission-mode acceptEdits --setting-sources ""
``

  1. Extension logs show the hooks/probe finishing within ~1s of launch, then ~59s of silence, then the timeout at exactly 60s (same shape as #60045 and #60342).

Workaround that avoids the broken probe path (any one):

  • Set claudeCode.useTerminal: true in user settings (runs Claude in an integrated terminal). Confirmed in #64168.
  • Use the CLI in a terminal, or the desktop app.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.168 (Claude Code) with 2.1.220 (VS Code extension)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Cursor

Additional Information

_No response_

View original on GitHub ↗

4 Comments

Venom-nexus · 26 days ago

Confirming this on Windows 10 too, via the VS Code Claude Code extension. Same exact error text, same intermittent pattern — sometimes launches clean, sometimes doesn't, no consistent trigger. Reproduced across multiple weeks and CLI versions (2.1.195 through 2.1.220), so this isn't a one-off or tied to a specific release.

My debug logs (View output logs in the extension) show the same underlying pattern as the now-closed #62327:

[Bootstrap] Fetch failed: ECONNABORTED
[ERROR] [Bootstrap] fetchBootstrapData failed: AxiosError: timeout of 5000ms exceeded
[ERROR] Failed to fetch MCP registry: timeout of 5000ms exceeded

Before landing on this as the likely root cause, I ruled out several other real-but-separate issues that were contributing noise on my end: stale .claude\ide\*.lock files from crashed sessions, a missing CLAUDE_CODE_GIT_BASH_PATH, a project-scoped playwright MCP server with its own 30s connection timeout, and orphaned chrome.exe processes from an interrupted Playwright install. Fixing each of those reduced frequency but never eliminated the failure. Also tried the full env var workaround block from #62327 (BUN_CONFIG_DISABLE_HTTP2, NODE_OPTIONS=--dns-result-order=ipv4first, etc.) — no measurable effect, consistent with what that issue's original reporter found.

Your finding about spawnConfigProbe() completing but its result never reaching the extension's initializationResult() acknowledgment lines up with what I'm seeing — the underlying config/session data often does complete successfully in the logs, it's specifically the acknowledgment back to the extension UI that seems to be the failure point. Happy to share full logs if it helps narrow this down further.

bcherny collaborator · 13 days ago

Thanks for the detailed report. We tried to reproduce this on the released 2.1.233 build, but the failure mode is Windows-only (native Windows + the VS Code/Cursor extension) and we can't currently exercise that setup on the machine we triaged from, so we can't confirm or rule it out ourselves. Reviewing the intended behavior: the extension is expected to start a session and apply a model change within a few seconds; a 60-second startup timeout is never expected, so we're treating this as a bug rather than a configuration problem, and we agree the "check authentication and network connectivity" wording is misleading for this case.

We haven't found a fix that landed after 2.1.220, so this is still open as far as we know. To narrow it down, could you (or anyone else hitting it) share:

  • The full "Claude Code" output-channel log from one failing launch (from extension activation through the 60s error), with anything sensitive redacted
  • Whether it happens on the current extension version (2.1.233), and roughly how often (every launch vs. intermittent)
  • Whether it still happens with all project/user MCP servers temporarily removed
  • The output of claude doctor from the same machine

If several of you can post logs from failing runs we can compare them for the common point where the handshake stalls.

🤖 Generated with Claude Code

github-actions[bot] · 13 days ago

We weren't able to reproduce this. Could you provide steps to trigger the issue — what you ran, what happened, and what you expected? This issue will be closed automatically if there's no activity within 7 days.

hugohamelcom · 13 days ago

Thanks for the detailed triage questions @bcherny. I've now isolated this to a concrete, reproducible mechanism rather than a random timeout, and I have evidence for each of your asks.

Answers to your four questions:

  1. Version / frequency: 2.1.231 CLI + 2.1.220 extension on Windows 11 (Cursor). Intermittent, but with a pattern: works after a reboot, then a new session fails later in the day, and killing/reopening Cursor doesn't fix it. That "fails later" signature is the tell — it tracks a debounced background job crossing its due-window, not auth or network.
  1. MCP removed: N/A. The failing config has zero MCP servers (mcpServers: {} in both ~/.claude.json and project settings). It reproduces with a clean default config, so MCP is ruled out.
  1. claude doctor: CLI, terminal, and desktop all work; only the extension's spawned subprocess hangs. The extension log shows OAuth tokens found in secure storage immediately before the 60s timeout, and the CLI answers claude -p fine.
  1. Log shape (the important part): SessionStart hooks finish ~1s after spawn, then there's ~59s of silence, then the kill at exactly +60.0s. The subprocess is alive and healthy after the kill — the log continues with [skills] idle — switching poll interval to 30000ms after the watchdog fired.

The mechanism I found (this is the actionable part):

The 60s gap between "hooks finished" and "init-complete ack" is real work the subprocess is still doing — SessionStart hooks, not an idle stall. On a hook-heavy repo the hook chain itself can consume the entire budget:

  • .claude/settings.json ran 8 SessionStart hooks totalling ~58s worst-case (measured per-hook with timestamps).
  • The dominant hook (a model router validation) launches a maintenance job with ( cmd ) &. The backgrounded subshell inherits the hook's stdout pipe, so the hook harness reads stdout until EOF and blocks until that detached job finishes — including a ~15s text classification and word representations model train and a live API canary. When the maintenance debounce stamp was stale, the hook alone took 30-60s. This is the classic "detached grandchild inherits the stdio pipe" hang #84864 describes, but on the SessionStart path, not MCP.
  • A second hook (a memory reader) spawned ~64 per-file git log processes ≈ 10s.
  • On Windows, antivirus real-time scanning multiplied every process spawn ~10x (measured printf at 632ms vs ~50ms with exclusions), turning dozens of hook spawns into extra seconds.

Repro you can run anywhere:

# time a single SessionStart hook under captured stdout (the hook's real condition)
time bash .claude/scripts/<sessionstart-hook>.sh

Before the fix: ~30-60s when maintenance is due. After fixing the backgrounded subshell to close its own fds (( cmd ) </dev/null >/dev/null 2>&1 &), the same hook returns in ~1.5s while the train runs detached.

The fix that resolved it (repo-side, no extension change needed):

  • ( bash ... ) </dev/null >/dev/null 2>&1 & — the trailing redirections belong to the subshell, not the inner command; without them the subshell holds the caller's stdout pipe open until it exits.
  • Batched the per-file git log calls in the memory hook into one pass (~10s → ~0.3s).
  • SessionStart chain went from ~58s to ~15s; after also excluding the repo + Git from the AV scan, ~10-12s.

What would help you fix the extension side: the watchdog kills at 60s even when the subprocess is healthy and still running hooks. A SessionStart hook chain that legitimately exceeds the budget is treated identically to a hung probe. Two cheap wins: (a) start the 60s clock after SessionStart hooks complete (or include hook time in the budget explicitly), and (b) when the timeout fires, report what the subprocess was last doing (its final log line before the kill) instead of blaming auth/network — every reporter here wasted days chasing the wrong subsystem.

Happy to share the full redacted output-channel log and the hook-timing harness if it helps correlate against your internal repro.