Task tool subagents don't terminate after completion, causing memory leak
Description
Subagent processes spawned by the Task tool don't terminate after completing their work, leading to significant memory accumulation over time.
Environment
- Claude Code version: 2.1.15
- OS: Ubuntu Linux 6.17.0-8-generic
- Node.js: v25.4.0
Observed Behavior
After a long session with moderate Task tool usage, we observed:
- 309 orphaned subagent processes
- ~110 GB RAM consumed (~400MB per subagent)
- Subagents remain alive indefinitely even after completing their task
Root Cause Analysis
Investigated file descriptors of a "completed" subagent:
fd 0 (stdin) → socket:[148731694] # IPC socket
fd 1 (stdout) → socket:[148731697] # IPC socket
fd 13 → anon_inode:[eventpoll] # Node.js event loop
fd 14 → anon_inode:[timerfd] # Timer
The issue: Subagents communicate with the parent via sockets. When the task completes:
- Subagent sends response to parent ✓
- Parent receives response ✓
- Parent should close the socket → subagent would receive EOF and exit
- But the socket is never closed → subagent's stdin never gets EOF
- Node.js event loop stays alive waiting for more input
- Subagent process lives forever
The parent process (main Claude) is still alive - subagents aren't orphaned in the Unix sense. The parent simply doesn't close the IPC socket after the task completes.
Reproduction
- Start a Claude Code session
- Use Task tool multiple times (e.g.,
subagent_type=Exploreorsubagent_type=general-purpose) - After tasks complete, check for lingering processes:
``bash``
pgrep -af "claude.*--output-format stream-json.*--disallowedTools"
- Observe processes remain alive with ~400MB RSS each
Expected Behavior
Subagent processes should terminate when:
- Their task is complete and response sent
- The parent closes the IPC socket
- Or after an idle timeout (e.g., 60 seconds of no communication)
Workaround
We created a cron job to periodically clean up orphaned subagents:
# Every 15 minutes
*/15 * * * * pkill -f "claude.*--output-format stream-json.*--disallowedTools"
Impact
- Memory exhaustion on systems with heavy Task tool usage
- Can consume 100+ GB RAM in long sessions
- Requires manual intervention or automated cleanup
Suggested Fix
- Parent should explicitly close the IPC socket when Task completes
- Add idle timeout to subagents (auto-exit after N seconds of no input)
- Use pipes instead of sockets (pipes EOF automatically when parent closes)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗