[BUG][Windows] npm-global auto-update leaks a ~240 MB claude.exe.old per failure and can leave no claude.exe at all (update_apply_exe_locked)
Not a duplicate of #74733, #69881 or #79467. #74733 and #69881 are the native installer reporting success while silently keeping the old launcher. #79467 shares theclaude.exe.old.<ts>artifact but is about a leftover process entering ataskkill/WMI loop. This report is the npm-global installer reporting failure (error_code: update_apply_exe_locked) and, intermittently, leaving noclaude.exeat all — plus unbounded accumulation of the.oldfiles, which nothing ever reaps.
Summary
On a Windows npm-global install, the auto-updater renames the running claude.exe to claude.exe.old.<epoch-ms> (necessary — Windows will not let it overwrite a running image), then writes the replacement. When that write fails, two things go wrong:
- Every failure leaks a ~240 MB binary that is never cleaned up. Deterministic.
- Sometimes it leaves no
claude.exeat all, breaking the install. Intermittent, and not self-healing — onlynpm install -g @anthropic-ai/claude-coderecovers it.
Environment
- Claude Code 2.1.248, Windows 11 Enterprise 26200, PowerShell 7
- npm-global install under nvm4w-managed Node v24.19.0 (
C:\nvm4w\nodejs)
Observed
The UI reports it:
Auto-update failed: claude.exe in use (close other Claude Code sessions, including VS Code)
Run claude doctor
~/.claude/.last-update-result.json:
{"timestamp":"2026-08-27T23:36:06.690Z","path":"npm-global","outcome":"failed",
"status":"install_failed","version_from":"2.1.247","version_to":"2.1.248",
"error_code":"update_apply_exe_locked"}
1. Orphan accumulation (deterministic)
node_modules/@anthropic-ai/claude-code/bin/
claude.exe.old.1787789613137 239 MB
claude.exe.old.1787869384441 242 MB
claude.exe.old.1787872481212 216 MB
481 MB currently sitting in one install, plus 315 MB in another. Nothing reaps these, including a subsequent successful update.
2. Missing binary (intermittent)
On 2026-08-27 at ~19:14 the rename happened and no replacement was written. bin/ held only .old files, and both shims broke:
'"C:\nvm4w\nodejs\node_modules\@anthropic-ai\claude-code\bin\claude.exe"'
is not recognized as an internal or external command
package.json still declares bin: {"claude": "bin/claude.exe"}, and npm still reported @anthropic-ai/claude-code@2.1.248 installed — the package metadata is fine, only the binary is gone.
A later failure the same evening left the binary intact, so this outcome is intermittent rather than guaranteed.
It does not recover on its own. I have a second install (%APPDATA%\npm) that failed this way on 2026-08-19 and was still broken 8 days later — it is not on PATH, so nothing ever surfaced it. The 2026-08-27 instance needed a manual npm install -g.
Why it stays hidden
Already-running sessions keep executing from their open handle (Windows permits renaming a running image), so nothing appears wrong until the next launch. In my case a periodic health check caught it 3 minutes later purely by accident; otherwise the first symptom would have been a shell that could not start Claude.
Secondary issues
- The suggested remediation cannot run. "Run
claude doctor" requires the binary that was just renamed away. - No failure history.
.last-update-result.jsonis a single-entry file overwritten each run, so nothing shows this has now happened twice. - Stale lock left behind.
~/.claude/.update.lockwas left holding a since-dead pid by the failed attempt.
Why it recurs
The precondition is "another process holds the exe". Anyone running multiple Claude Code sessions, or Claude Code alongside the VS Code extension, meets it essentially always. Twice in one week here.
Suggested fixes
- Write the replacement under a temp name and swap last, so a failure can never remove the working binary; or roll the rename back on any failure path.
- Reap
*.old.*binaries after a successful update (and on startup). - Detect a missing
bin/claude.exeat startup and self-repair, or print the exactnpm install -gcommand instead ofclaude doctor. - Clear
.update.lockwhen the recorded pid is dead.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗