[BUG] VS Code extension spawns two `claude` CLI processes per launch, which collide on `~/.claude.json`
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
Summary
Every session launch from the VS Code extension starts two full claude CLI processes within ~30 ms of each other. Both run the complete startup sequence and both write ~/.claude.json, which produces a hard lock error. Reproducible on extension versions 2.1.77, 2.1.257 and 2.1.263.
Environment
- Extension versions reproduced on: 2.1.77, 2.1.257, 2.1.263
- VS Code Remote-SSH to a Linux host (extension host and CLI both run on the remote host)
- Model: claude-sonnet-5
Observed behaviour
A single user turn produces two spawns — one for the resumed session, one with no resume id (this appears to be the "Loading config cache by launching Claude…" prefetch):
12:41:38.641 [info] Spawning Claude with SDK query function - permission mode: default, version: 2.1.77, resume: undefined
12:41:38.675 [info] Spawning Claude with SDK query function - permission mode: default, version: 2.1.77, resume: <session-id>
Both then run the full startup path — MCP config loading, LSP manager init, ripgrep self-test, bootstrap fetches, telemetry init — and both write the shared config file. The two processes interleave several writes within about one second, and the lock fails outright:
10:41:40.844 [DEBUG] Writing to temp file: ~/.claude.json.tmp.11264.<id>
10:41:40.848 [DEBUG] File ~/.claude.json written atomically
10:41:40.848 [ERROR] Failed to save config with lock: Error: Lock file is already being held
10:41:40.850 [DEBUG] Writing to temp file: ~/.claude.json.tmp.11263.<id>
10:41:40.851 [DEBUG] File ~/.claude.json written atomically
On 2.1.263 the same collision surfaces as a debug line instead of an error:
[DEBUG] Lock acquisition took longer than expected - another Claude instance may be running
Because each process writes the whole config file, the second write can silently discard changes made by the first.
Expected behaviour
One launch should start one CLI process, or — if a separate lightweight process is genuinely needed to warm the config cache — it should not run the full startup path and should not race the session process for the config lock.
Impact
- Full CLI startup cost is paid twice per launch. On a remote host over SSH, where per-syscall latency is higher, this is a noticeable share of the time before the first token.
- Concurrent writes to
~/.claude.jsonrisk lost updates, since each process writes the complete file rather than merging. - The
Failed to save config with lockerror is surfaced at ERROR level with no user-visible handling.
Steps to reproduce
- Open a workspace with a resumable session in the VS Code extension.
- Send any prompt.
- In the "Claude Code" output channel, observe two
Spawning Claude with SDK query functionlines close together — one withresume: <id>, one withresume: undefined. - Observe interleaved
Writing to temp file: ~/.claude.json.tmp.<pid>.<id>lines from two different PIDs, followed byFailed to save config with lockorLock acquisition took longer than expected.
Possibly related
[ERROR] MCP server "claude-vscode" Failed to fetch tools: MCP error -32601: Method not found appears on every launch on 2.1.77. On 2.1.257 and 2.1.263 the corresponding line is [WARN] claude-vscode notification channel error: Received a response for an unknown message ID: {"jsonrpc":"2.0","result":{},"id":0}. The suppression note in that warning ("further channel errors are not logged this session") appears to be scoped per spawned process rather than per extension-host session, so the warning recurs on every launch.