[BUG] Windows: idle session spins at 100% CPU after a watched ~/.claude directory is permanently deleted (libuv fs.watch bug; fix already merged upstream)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 16, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

On Windows, an idle Claude Code session spins at ~100% of one core indefinitely. Root-caused it with a debugger-grade forensic pass: it's the known libuv fs.watch bug where permanently deleting a watched directory sends the ReadDirectoryChangesW loop into an infinite error-retry spin — and Claude Code both watches and permanently deletes directories under ~/.claude, so it can trigger the bug against itself.

Evidence (captured live on the spinning process, v2.1.211, Windows 11 10.0.26200, NTFS):

  • Idle interactive session pinned at ~116% of one core; main thread accumulated 1h27m CPU.
  • ~500,000 "Other" I/O operations/second with zero read/write operations — the signature of a ReadDirectoryChangesW fail/retry loop on a dead handle, not real work.
  • Sysinternals handle shows the process holding an open handle to C:\$Extend\$Deleted\<FRN> — a watched directory that was POSIX-deleted while the watcher held its handle. NTFS USN journal dates the deletion and places the directory as a direct child of C:\Users\<user>\.claude\.
  • The process also holds watch handles on ~/.claude and ~/.claude\tasks\<uuid>. Claude Code deletes completed task dirs itself, so any session can strand its own watcher.
  • Identical signature confirmed independently on the same machine in VS Code's fileWatcher utility process (also Node/libuv), stranded by the same deletion — see microsoft/vscode#287800.
  • Healthy idle sessions on the same machine measure 0–0.2% of a core; a stranded one never recovers until the process exits. Sessions resume cleanly afterward (claude --resume).

Root cause and fix status

  • Upstream Node.js issue: nodejs/node#61398 (fs.watch: endless events; confirmed trigger is permanent deletion — Recycle Bin moves don't trigger it).
  • Fix already merged in libuv master on 2026-03-31: libuv/libuv#5013 (44125af6, "win: fix watch loop logic") — but it is in no libuv release yet (latest v1.52.1 predates it) and not cherry-picked into Node's deps/uv.

Since Claude Code bundles its own Node runtime, you don't have to wait for the libuv → Node → release chain: cherry-picking libuv/libuv@44125af6 into the bundled runtime fixes it immediately.

Workarounds until then

  • Avoid permanently deleting watched dirs (in Claude Code's own case: task-dir cleanup under ~/.claude/tasks is a self-trigger).
  • Detect the spin signature (>0.8 core AND >50k other-ops/s AND ~0 read/write ops) and restart the session; claude --resume restores it.

Possibly related (macOS reports, cause there unconfirmed): #75630, #17148

What Should Happen?

An idle session should stay near 0% CPU; deleting a watched directory should not put the file watcher into an infinite syscall loop.

View original on GitHub ↗