claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

Memory leak: Missing cleanup for /tmp/claude-*-cwd working directory tracking files

Open Sundeepg98 opened this issue 2 months ago • 4 comments

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

  1. Claude Code generates a random temp file path: let K = \${V}/claude-${F}-cwd``
  2. Appends pwd -P >| ${K} to every Bash command to capture final directory
  3. Reads the file with bq6(K,{encoding:"utf8"}) to update internal cwd
  4. 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

  1. Run any Bash command: ls
  2. Check temp files: ls /tmp/claude-*-cwd
  3. Observe new file created but not deleted
  4. Repeat and watch accumulation

Why This Design Exists

The temp file approach is actually clever and necessary:

  • Tracks cd commands 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

Sundeepg98 avatar Oct 03 '25 15:10 Sundeepg98

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

  1. Multi-user systems: Shared servers could accumulate thousands of files
  2. Long-running sessions: Power users running Claude Code 24/7
  3. CI/CD environments: Automated systems without regular reboots
  4. 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!

Sundeepg98 avatar Oct 03 '25 15:10 Sundeepg98

Have we resolved this issue?

KCW89 avatar Nov 04 '25 05:11 KCW89

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.

github-actions[bot] avatar Dec 09 '25 10:12 github-actions[bot]

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.

erykwieliczko avatar Dec 22 '25 22:12 erykwieliczko