[BUG] Session scratchpads under /tmp/claude-<uid> never garbage-collected after exit — 8.8 GB of dead sessions resident in RAM on tmpfs, drives swap thrashing
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Each session creates a scratchpad directory under /tmp/claude-<uid>/<project-slug>/<session-id>/. These are never removed: no cleanup on graceful exit, no startup sweep for crash leftovers, no size/age cap. On distros where /tmp is tmpfs (RAM-backed — the Ubuntu default), every exited session's scratchpad permanently consumes RAM, and under memory pressure those dead pages get swapped out, directly causing swap thrashing.
Measured on one machine (2026-07-07, Ubuntu 26.04, 61G RAM, /tmp = 31G tmpfs):
/tmpheld 24 GB, of which 22 GB was/tmp/claude-1000/.- Classified every session dir by liveness — a dir is dead iff no running process's environment carries its
CLAUDE_CODE_SESSION_ID(children inherit it, so scanning/proc/*/environis an exact signal): - 95 dead sessions = 8.8 GB (leak)
- 24 live sessions = 13.3 GB (legitimately in use)
- Deleting only the dead dirs: RAM used 42→38 Gi, swap 7.7 Gi (96% full) → 2.8 Gi (35%). Swap dropped more than RAM — the dead scratchpads had been paged out and were the direct cause of system-wide thrashing.
Two important notes for whoever fixes this:
- mtime is NOT a safe deletion heuristic. The single largest scratchpad (9.7 GB, mtime 3 days stale) belonged to a live session. Only the session-ID liveness check is safe.
- This is distinct from the (also stale-closed, never fixed) unbounded-growth-during-session family: #40108, #42125, #42388, #47771, #51814. Those are about size during a running session; this report is about dead sessions never being reaped at all. Related open issue for a different artifact with the same no-GC lifecycle: #8856 (
/tmp/claude-*-cwdtracking files).
Discovery condition: this only becomes visible to users who run many/long-lived sessions — short-session users never accumulate enough to notice, which is likely why it has survived. Suggest adding session-lifetime/accumulation as a test dimension.
What Should Happen?
A session's scratchpad should be reclaimed when the session ends:
- Remove the scratchpad dir on graceful exit.
- Startup GC for crash/
killleftovers: sweep/tmp/claude-<uid>, delete any session dir whose ID is not referenced by any live process'sCLAUDE_CODE_SESSION_ID(exact and concurrent-session-safe). - Size/age cap as a backstop.
Error Messages/Logs
$ df -h -t tmpfs | grep -E '/tmp$'
tmpfs 31G 24G 7.3G 77% /tmp
$ du -sh /tmp/claude-1000
22G /tmp/claude-1000
$ free -h # before cleanup
Mem: 61Gi used 42Gi ... Swap: 8.0Gi used 7.7Gi
$ # liveness-checked purge of 95 dead session dirs (8.8 GB) — live sessions untouched
$ free -h # after cleanup
Mem: 61Gi used 38Gi ... Swap: 8.0Gi used 2.8Gi
Steps to Reproduce
- On a machine where
/tmpis tmpfs, run Claude Code sessions over several days (start and exit many sessions; heavy tool use grows the scratchpads). du -sh /tmp/claude-$(id -u)— observe monotonic growth; exited sessions' dirs are still present.- Build the live-session set:
for e in /proc/[0-9]*/environ; do tr '\0' '\n' < "$e" 2>/dev/null; done | grep -oE 'CLAUDE_CODE_SESSION_ID=\S+'and compare against the dirs on disk — every session dir not in the live set is leaked.
Environment
- Claude Code 2.1.202 (native install), also observed under 2.1.198–2.1.201
- Ubuntu 26.04 LTS, kernel 7.0.0-22-generic, x86_64
/tmp= tmpfs 31G (default), 61G RAM
Investigated and measured with Claude Code itself; full methodology available on request.