[BUG] Session bound to an empty/unregistered worktree pins a CPU core at 100% - no-backoff .claude lookup with an absolute-onto-absolute path join (Windows)
Summary
A Claude Code session whose cwd is bound to an empty, git-unregistered worktree directory enters an unbounded retry loop looking for <cwd>/.claude. It pins one CPU core at 100% indefinitely, issuing roughly 400,000 failed CreateFile calls per second. It never recovers on its own - the process has to be killed. It ran for 90+ minutes on my machine before I tracked it down.
Environment
- Windows 11, AMD Ryzen 9 9950X3D (16C/32T)
- Claude Code 2.1.219, headless session spawned by the Claude desktop app (1.24012.9)
- Session flags:
--output-format stream-json --input-format stream-json --permission-mode bypassPermissions --include-partial-messages
Symptom
One thread - the main event-loop thread, created at process start - sits permanently in State: Running:
| metric | affected session | identical sibling session |
|---|---|---|
| CPU | 1.00 core, continuously | normal, mostly Wait |
| kernel / user time | 1:06:49 / 0:18:07 (79% kernel) | - |
| context switches | 3,345,594 | - |
| I/O "other" ops/sec | 395,382 | 9 |
| I/O reads / writes per sec | 4 / 0 | 4 / 0 |
The sibling had a byte-identical command line, the same MCP servers, and was started 15 minutes apart - so this is not configuration-dependent.
Thread stack
0 0x0000000000000000
1 ntdll.dll!ZwDelayExecution+0x14
2 ntdll.dll!RtlDelayExecution+0x34
3 KERNELBASE.dll!SwitchToThread+0x1b
4 claude.exe!uv_key_delete+0x1d2af1
5 claude.exe!uv_key_delete+0xe6628
6 claude.exe!uv_key_delete+0xe6718
...
SwitchToThread in a tight loop - a spin-wait that never blocks. (uv_key_delete is merely the nearest exported symbol; the binary is a bundled Node SEA without symbols.)
The actual loop (Process Monitor)
Two CreateFile calls alternating, hundreds of thousands of times per second:
...\.claude\worktrees\priceless-swartz-4f20aa\.claude
-> NAME NOT FOUND
...\worktrees\priceless-swartz-4f20aa\.claude\D:\AI Projects\TLG2\.claude\worktrees\priceless-swartz-4f20aa\.claude
-> NAME INVALID
Two distinct defects are visible:
- Absolute-onto-absolute path join. The second path is the cwd joined onto itself. On Windows
path.join()does not reset on a drive letter the way POSIX does on a leading/, so the result contains a colon mid-path and is structurally invalid - it can never resolve, no matter what exists on disk. - No backoff on the retry. The lookup is retried in a tight
SwitchToThreadloop: no delay, no attempt cap, no error surfaced.
How the session got into this state
~/.claude/sessions/<pid>.json contained:
{"cwd":"D:\\AI Projects\\TLG2\\.claude\\worktrees\\priceless-swartz-4f20aa","name":"priceless-swartz-4f20aa-4f"}
That directory existed but was completely empty, and was registered in neither git worktree list nor .git/worktrees. Every sibling worktree in the same folder contains a full checkout plus a .claude directory. So worktree creation appears to have failed partway through, and the session was bound to the resulting empty husk as its cwd regardless.
Partial confirmation
Creating the missing <cwd>/.claude directory by hand dropped the syscall rate from ~395,000/sec to ~115,000/sec, but did not stop the spin - consistent with the analysis above, since the malformed second path cannot succeed under any filesystem state.
Expected behaviour
- Don't bind a session to a worktree whose creation didn't complete, or that isn't registered in git - fail loudly at session start instead.
- Fix the absolute-onto-absolute path join in the settings/config lookup.
- Bound the retry: backoff, an attempt cap, and a surfaced error rather than an infinite hot loop.
Workaround
Kill the session process. There is no in-session recovery, and the CPU burn continues until it exits.