Atomic-write leaves `.tmp.<pid>.<hex>` residuals (Edit/Write + plugin LSP), and plugin `.in_use` lock files leak on process exit — Windows (follow-up to #60146)

Open 💬 0 comments Opened Jun 16, 2026 by yamachang1011-cmyk

Summary

Follow-up to #60146, which was auto-closed by the stale bot on 2026-06-16 without ever being triaged or answered. The behavior still reproduces, and I've characterized a second, related leak since the original report. Filing fresh per the stale bot's guidance ("open a new issue if this is still relevant"), consolidating both.

There are two related residual leaks under ~/.claude on Windows, both rooted in atomic-write / cleanup-on-exit:

  1. Edit/Write atomic-write residuals<filename>.tmp.<pid>.<hex> files remain after the tool call returns success (the original #60146 report).
  2. Plugin LSP lock-directory leak — the bundled pyright-lsp / typescript-lsp reference-count lock dirs (.in_use/) both (a) contain the same .tmp.<pid>.<hex> atomic-write residual, and (b) leak their settled lock files on process exit.

Current census (Windows 11, Git Bash harness, 2026-06-16)

Strict match to the two original patterns (.tmp.<pid>.<hex> and .tmp.<hex>):

| Location | .tmp.<pid>.<hex> residuals |
|---|---|
| plans/ | 39 |
| projects/<hash>/memory/ | 14 |
| .credentials.json.tmp.<hex> (root) | 2 |
| plugin LSP .in_use/ dirs | 286 |
| total | 347 |

Plus 504 settled lock files in the plugin LSP lock dirs (252 in each of pyright-lsp / typescript-lsp .in_use/). The original report observed 412 atomic-write residuals; they accumulate continuously.

Leak 1 — Edit/Write atomic-write residuals (original #60146)

Editing/creating a file via Edit/Write leaves a <filename>.tmp.<pid>.<hex> residual in the directory after the call returns success. Two suffix shapes observed:

  • <filename>.tmp.<pid>.<hex> — e.g. MEMORY.md.tmp.133200.e9386df7a3af (most files)
  • <filename>.tmp.<hex> — e.g. .credentials.json.tmp.<hex> (credentials file only, no PID segment)

Repro:

  1. Edit any file (e.g. ~/.claude/CLAUDE.md).
  2. find <dir> -name '*.tmp.*' → residual remains, mtime ~seconds before the final file, never cleaned.
  3. Across sessions these accumulate (one extended setup reached 412). Full original detail in #60146.

Leak 2 — plugin LSP .in_use/ lock directories (new)

Path: ~/.claude/plugins/cache/claude-plugins-official/{pyright-lsp,typescript-lsp}/<ver>/.in_use/

Two compounding problems:

  1. Same atomic-write residual as Leak 1: 286 of the 347 residuals above live inside these two .in_use/ dirs — the lock mechanism uses the same atomic write and leaves the same .tmp.<pid>.<hex> residual.
  2. Cleanup-on-exit leak of settled lock files: the lock files ({"pid","procStart"} JSON, named by PID) are not removed on process exit and accumulate unbounded. A liveness audit of one 6,874-file snapshot across 12 plugin dirs — cross-checking each lock's (pid, procStart) pair against running processes — found 0 active / 100% leaked (every PID-number match was coincidental reuse; procStart differed). After deleting 6,856, they re-accumulated to 504 within ~17 hours, indicating an active leak. The live LSP servers do not appear to hold these as live locks.

Environment

  • Claude Code CLI: bundled (...\AppData\Roaming\Claude\claude-code\<version>\claude.exe); originally observed 2.1.138, still reproducing 2026-06-16.
  • OS: Windows 11, Git Bash shell harness.
  • Affected dirs: ~/.claude/projects/<hash>/memory/, plans/, rules/, skills/, scripts/, root .credentials.json.tmp.*, and plugins/cache/.../{pyright,typescript}-lsp/<ver>/.in_use/.

Additional environment finding — PowerShell Remove-Item silently blocked

Cleaning these residuals via PowerShell Remove-Item is silently blocked (no error; the count is unchanged afterward), apparently by a sandbox/file guard. Deletion only succeeds via Git Bash find ... -delete. Flagging for anyone scripting a Windows cleanup hook.

Workaround (manual, per session)

find ~/.claude -name '*.tmp.*' \
  \( -regextype posix-extended -regex '.*\.tmp\.[0-9]+\.[a-f0-9]+$' -o -regex '.*\.tmp\.[a-f0-9]+$' \) \
  -mmin +5 -delete 2>/dev/null
# plugin lock leak: separately delete settled lock files under .in_use/ older than a few minutes

Questions

  1. Intent — is .tmp.<pid>.<hex> an intentional atomic-rename artifact, or a cleanup miss after rename?
  2. Atomicity — is tmp → final rename guaranteed atomic, i.e. safe to delete residuals matching the patterns after the tool call returns?
  3. Cleanup timing — for a PostToolUse hook, is find ... -mmin +5 -delete safe, or could it race an in-progress transaction?
  4. Schema — a 2026-04-24 observation showed suffix <timestamp_ms>; 2026-05-18 onward shows <hex>. Intentional change? Is the hex a UUID, random, or other?
  5. .in_use lock lifecycle — should plugin lock files be removed on process exit? If so, Leak 2 is a bug; if not, what is the intended GC path?

Impact

Disk: small per file (~5–100 KB) but hundreds–thousands across long-running setups. Clutters ls / find. Requires per-session manual cleanup if not automated. The plugin .in_use leak grows fastest (6,874 in extended use; 504 within ~17h of a clean).

Happy to provide a full listing, the liveness-audit script, or a minimal repro. Thanks!

View original on GitHub ↗