Memory leak: Missing cleanup for /tmp/claude-*-cwd working directory tracking files
Bug Description
Claude Code creates temporary files to track working directory changes across Bash command executions but never deletes them, causing accumulation of /tmp/claude-*-cwd files.
Environment
- Claude Code Version: 2.0.1
- OS: Linux (WSL2)
- Node Version: (System default)
The Problem
Every Bash tool invocation creates a temporary file at /tmp/claude-{random-4-hex}-cwd to track the working directory after command execution. These files are never cleaned up, leading to accumulation.
Evidence
- Observed: 174 files accumulated in one day of usage
- Pattern: Each file is 22 bytes containing the working directory path
- Debug log: Shows 2,018 Bash invocations over 4 days
- Only cleanup: systemd-tmpfiles-clean removes them daily at 07:15
Root Cause Analysis
Location in Code
File: /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js
The issue is in the lq6 function (around line 1520 in the minified code):
// Current implementation (BUG - no cleanup):
P.result.then(async(k)=>{
if(k&&!Y&&!k.backgroundTaskId)try{
j$(bq6(K,{encoding:"utf8"}).trim(),M) // Reads file but never deletes it
}catch{
B1("tengu_shell_set_cwd",{success:!1})
}
})
The Mechanism
- Claude Code generates a random temp file path:
let K = \${V}/claude-${F}-cwd`` - Appends
pwd -P >| ${K}to every Bash command to capture final directory - Reads the file with
bq6(K,{encoding:"utf8"})to update internal cwd - Missing step: Never calls
unlinkSync(K)to delete the file
The Fix
Add cleanup immediately after reading the file:
// Fixed implementation:
P.result.then(async(k)=>{
if(k&&!Y&&!k.backgroundTaskId)try{
let cwdContent=bq6(K,{encoding:"utf8"}).trim();
try{C1().unlinkSync(K)}catch{}; // <- Add this line
j$(cwdContent,M)
}catch{
B1("tengu_shell_set_cwd",{success:!1})
}
})
Verification
I applied this fix locally and confirmed:
- Files are now created and immediately deleted after use
- Working directory tracking continues to function correctly
- No accumulation even after running 15+ commands in succession
Impact
- Resource leak: Accumulates filesystem entries (500+ files/day for heavy users)
- Privacy concern: Working directory paths persist in /tmp
- Disk usage: While minimal (22 bytes each), it's unnecessary accumulation
Reproduction Steps
- Run any Bash command:
ls - Check temp files:
ls /tmp/claude-*-cwd - Observe new file created but not deleted
- Repeat and watch accumulation
Why This Design Exists
The temp file approach is actually clever and necessary:
- Tracks
cdcommands across subprocess isolation - Doesn't pollute stdout with pwd output
- Works reliably across all shell types
- The implementation is 95% correct, just missing the cleanup step
Recommendation
This is a simple one-line fix that should be included in the next Claude Code release. The temp file mechanism itself is sound and necessary for stateful directory navigation in a stateless subprocess model.
Additional Notes
- The fix has been tested and verified locally
- No side effects observed
- This affects all Claude Code users on Unix-like systems
Additional Analysis & Impact Assessment
Quantitative Impact Data
After monitoring for 24 hours, here's the accumulation rate:
- 174 orphaned files created in ~12 hours of usage
- 2,018 Bash invocations tracked in logs
- ~14.5 files/hour accumulation rate during active use
- 22 bytes each = minimal individual impact but compounds over time
Why This Matters
- Multi-user systems: Shared servers could accumulate thousands of files
- Long-running sessions: Power users running Claude Code 24/7
- CI/CD environments: Automated systems without regular reboots
- Docker containers: May not have systemd-tmpfiles-clean
Reproduction Script
#!/bin/bash
# Monitor temp file accumulation
echo "Starting temp file monitor..."
INITIAL_COUNT=$(ls /tmp/claude-*-cwd 2>/dev/null | wc -l)
echo "Initial count: $INITIAL_COUNT files"
# Trigger some Bash commands through Claude Code
for i in {1..10}; do
# This would need to be triggered through Claude Code's UI/API
echo "Trigger Bash command #$i through Claude Code"
sleep 1
done
FINAL_COUNT=$(ls /tmp/claude-*-cwd 2>/dev/null | wc -l)
echo "Final count: $FINAL_COUNT files"
echo "Accumulated: $((FINAL_COUNT - INITIAL_COUNT)) new files"
Suggested Priority
Given the silent nature of this bug (no errors, just accumulation), I'd suggest Medium Priority with the following reasoning:
- ✅ Has a simple one-line fix
- ✅ Affects all users universally
- ⚠️ No immediate functionality impact
- ⚠️ Mitigated by system cleanup on most Linux distros
- ❌ Could cause issues on constrained systems
Testing the Fix
The fix has been verified locally by modifying /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js:
// After line containing readFileSync(K)
try { require('fs').unlinkSync(K) } catch {}
Happy to provide any additional information or testing assistance needed!
Have we resolved this issue?
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
The issue still persists and is really annoying. After a few days the amount of claude-*-cwd files reaches thousands which really slows things down.