Task tool subagents don't terminate after completion, causing memory leak

Resolved 💬 3 comments Opened Jan 22, 2026 by Guliver2-Magic Closed Jan 25, 2026

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:

  1. Subagent sends response to parent ✓
  2. Parent receives response ✓
  3. Parent should close the socket → subagent would receive EOF and exit
  4. But the socket is never closed → subagent's stdin never gets EOF
  5. Node.js event loop stays alive waiting for more input
  6. 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

  1. Start a Claude Code session
  2. Use Task tool multiple times (e.g., subagent_type=Explore or subagent_type=general-purpose)
  3. After tasks complete, check for lingering processes:

``bash
pgrep -af "claude.*--output-format stream-json.*--disallowedTools"
``

  1. 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

  1. Parent should explicitly close the IPC socket when Task completes
  2. Add idle timeout to subagents (auto-exit after N seconds of no input)
  3. Use pipes instead of sockets (pipes EOF automatically when parent closes)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗