CLI hangs at loading animation when zombie claude.exe processes hold .claude.json.lock (Windows)
Summary
On Windows 11, multiple zombie claude.exe processes accumulate over a session and saturate global locks (notably ~/.claude.json.lock), preventing new Claude Code sessions from initializing. Symptom: the CLI shows the loading animation indefinitely.
Environment
- OS: Windows 11 Famille 10.0.26200 (build 26200)
- Architecture: x64
- Claude Code: 2.1.136
- Node: v25.8.0
- PowerShell: 5.1.26100.8328
- Shell host: VS Code integrated terminal (PowerShell)
- RAM: 31.6 GB total, ~9.7 GB free at incident time
Symptom
Three claude sessions running in three separate VS Code instances, each in a different project. After a few hours, attempting to open a new Claude Code session (in a 4th project, or after closing/reopening one of the existing ones) results in:
- Terminal shows the Claude Code loading animation
- Hangs indefinitely (never reaches the prompt)
- Affects ALL projects (tested across two different projects), so it's a global issue, not project-specific
User has to kill all claude.exe processes manually to recover.
Diagnostic
After ~3 hours of normal use (PC booted ~19:30, multi-session work across 3 VS Code windows), I observed:
- 13 active
claude.exeprocesses (vs 3 expected for 3 active sessions) - A group of 8 processes (1 parent + 7 children) reparented to
sihost.exe(Windows Shell Session Host) — strong indicator of orphaned subagent/MCP workers whose original parent (a VS Code instance) was closed without graceful claude shutdown - Process tree of the orphan group:
````
PID 17056 (claude, parent: sihost.exe 38632, age 3h00, 88s CPU, 275 MB)
PID 21428 (claude, age 3h00, 0s CPU, 29 MB) <- idle worker
PID 25236 (claude, age 3h00, 280s CPU, 165 MB) <- did real work
PID 7920 (claude, age 3h00, 5s CPU, 61 MB)
PID 53784 (claude, age 3h00, 0.3s CPU, 75 MB)
PID 10600 (claude, age 3h00, 0.2s CPU, 69 MB)
PID 48916 (claude, age 3h00, 0.9s CPU, 95 MB)
PID 35176 (claude, age 3h00, 7s CPU, 116 MB)
C:\Users\steev\.claude.json.lockwas present at one point during diagnosis (held by one of the orphans) — this is the global config lock that all sessions need to read/write, which would explain why new sessions hang on startup.- Multiple stale
~/.claude/sessions/{pid}.jsonfiles for already-dead processes (18792.json, 50572.json, 52252.json) ~/.claude/projects/subagents/contained many recentagent-XXfiles matching the pattern of Task tool subagents — confirming the orphan group is a Task subagent fan-out that survived its parent.
User confirmed they did not manually start claude from the Start menu — they only opened VS Code instances after booting the PC. The orphan group's parent being sihost.exe is consistent with automatic reparenting that Windows performs when a child outlives its parent (the original VS Code or its terminal host process).
Root cause hypothesis
When a VS Code window hosting a Claude Code session is closed while subagents (Task tool) or MCP workers are running, the root claude.exe exits but the spawned children are not terminated cleanly. Windows reparents them to sihost.exe. They keep:
- holding the
.claude.jsonadvisory lock periodically (write-back of session state, settings sync) - writing to
~/.claude/plugins/cache/*/.in_use/plugin cache markers - consuming handles and file descriptors
After accumulating enough orphans (~5-10), lock contention prevents new sessions from completing initialization within the startup timeout.
Reproduction (suspected, not deterministically tested)
- Open VS Code, start
claudein integrated terminal - Trigger a long-running Task tool subagent (e.g.,
Exploreorgeneral-purposeagent across many files) - While the subagent is running, close the entire VS Code window (X button, not graceful Ctrl+C in the claude terminal first)
- Repeat across multiple VS Code instances over a few hours
- Try to start a fresh
claudesession in any project → infinite loading animation
Workaround used to recover
# Identify the current session PID, kill the rest
Get-Process claude | Where-Object { $_.Id -ne <CURRENT_PID> } | Stop-Process -Force
# Clean stale lock if present
Remove-Item C:\Users\steev\.claude.json.lock -Force -ErrorAction SilentlyContinue
# Clean stale session files
Get-ChildItem C:\Users\steev\.claude\sessions | Where-Object {
-not (Get-Process -Id $_.BaseName -ErrorAction SilentlyContinue)
} | Remove-Item -Force
# Clean stale .in_use markers
Get-ChildItem C:\Users\steev\.claude\plugins\cache -Recurse -Force |
Where-Object { $_.Directory.Name -eq '.in_use' -and -not (Get-Process -Id $_.Name -ErrorAction SilentlyContinue) } |
Remove-Item -Force
After this, new sessions launch instantly. RAM also dropped from ~22 GB used to ~18 GB used.
Suggested fixes
- Graceful shutdown on parent death: register a Windows Job Object with
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, or useprocess.on('exit')cascade, so childclaude.exe/ MCP workers terminate when the root process dies. This is the most direct fix. - Stale lock detection: when acquiring
.claude.json.lock, check if the holder PID is still alive; if not, force-release and warn. - Startup self-cleanup: on
claudestart, scan~/.claude/sessions/*.jsonand.in_use/*for dead PIDs and clean them automatically. - Better diagnostic on hang: if startup waits >5s for the config lock, surface a message naming the holder PID instead of hanging silently — would have made this self-diagnosable in seconds.
Additional context
User is a power user running 3+ Claude Code sessions concurrently across multiple VS Code instances daily. This issue is reproducible enough that the user notices it after a few hours of work. Happy to provide further diagnostics, full process trees, or test fixes.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗