Session freezes indefinitely when multiple background agents + blocking TaskOutput

Resolved 💬 6 comments Opened Jan 11, 2026 by aaaaaandrew Closed Mar 2, 2026

Bug Report: Session Freeze When Multiple Background Agents + Blocking TaskOutput

Description

Claude Code session freezes indefinitely when launching multiple background agents using the Task tool with run_in_background: true, and then calling TaskOutput with block: true on all of them. The session becomes completely unresponsive and never recovers, even though the TaskOutput calls specify a 60-second timeout.

Environment

  • Claude Code Version: 2.1.4
  • Platform: macOS Darwin 25.2.0 (arm64)
  • Installation: Homebrew cask

Steps to Reproduce

  1. Launch 4 background agents using the Task tool with run_in_background: true
  2. Have the main session call TaskOutput with block: true and timeout: 60000 on all 4 agents
  3. Observe that the session freezes indefinitely

This can be triggered by any workflow that spawns multiple background agents and then waits for their results.

Expected Behavior

  • TaskOutput should return after the 60-second timeout if agents haven't completed
  • If agents fail or stop unexpectedly, TaskOutput should detect this and return an error
  • The session should remain responsive

Actual Behavior

  • Session freezes completely with "Waiting for task" displayed for all agents
  • TaskOutput never returns despite the timeout parameter
  • No error messages are shown
  • Only recovery is to kill the process (Ctrl+C or kill <PID>)

Root Cause Analysis from Debug Logs

I investigated the debug logs and found several issues:

1. All API Streams Interrupted Simultaneously

All 4 background agents AND the main session have "stop_reason": null in their final API responses. This indicates API streams were interrupted mid-response.

Example from one agent's log:

{
  "message": {
    "content": [{"type": "text", "text": "Let me retry the query with better error handling:"}],
    "stop_reason": null,
    "stop_sequence": null
  }
}

The stop_reason should be "tool_use" or "end_turn", not null.

2. High Concurrent API Load

Debug log analysis:

  • 57 API requests made
  • 54 streams started
  • 0 stream completion or error messages logged
  • Multiple streams starting at nearly the same millisecond

This suggests resource exhaustion or connection limits when 5 concurrent API sessions (1 main + 4 agents) are all active.

3. TaskOutput Never Times Out

Debug log shows PreToolUse hooks fired for all 4 TaskOutput calls:

[DEBUG] executePreToolHooks called for tool: TaskOutput
[DEBUG] executePreToolHooks called for tool: TaskOutput
[DEBUG] executePreToolHooks called for tool: TaskOutput
[DEBUG] executePreToolHooks called for tool: TaskOutput

But there are NO corresponding:

  • PostToolUse hooks
  • Completion messages
  • Timeout errors
  • Any subsequent log entries

4. Agents Died Mid-Execution

All 4 agents stopped at approximately the same time while in the middle of work:

  • Agent 1: Said "Let me retry..." but never issued the next tool call
  • Agent 2: Issued Bash commands but never received results
  • Agent 3: Received an error response but never processed it
  • Agent 4: Was mid-sentence in its response

Timeline

| Relative Time | Event |
|---------------|-------|
| T+0s | 4 Task tools called to launch background agents |
| T+0s | All 4 agents launched successfully |
| T+6-8s | Main session calls 4 TaskOutput tools with block: true |
| T+15s | Last debug log entry - streams started but never completed |
| T+∞ | Session remains frozen (well past 60s timeout) |

Suspected Issues

  1. Race condition in TaskOutput blocking logic: TaskOutput may be waiting on a condition that will never be satisfied when agents die unexpectedly
  1. No heartbeat/liveness check for agents: TaskOutput doesn't detect that agents have stopped producing output to their log files
  1. Concurrent API connection limit: 5 simultaneous API sessions may exceed some internal or API-side limit, causing all streams to fail silently
  1. Missing error propagation: When agent streams fail with stop_reason: null, this error state isn't propagated to TaskOutput
  1. Timeout not implemented correctly: The timeout parameter on TaskOutput appears to have no effect when agents are in a broken state

Suggested Fixes

  1. Implement agent liveness detection: TaskOutput should check if the agent log file is still being written to, and timeout if no new entries for X seconds
  1. Add stream health monitoring: Detect when streams have stop_reason: null and treat as an error condition
  1. Limit concurrent agent API calls: Queue agent requests or implement backpressure to prevent overwhelming the API
  1. Improve timeout handling: Ensure TaskOutput timeout actually fires even when the underlying agent is in an inconsistent state
  1. Add graceful degradation: If an agent fails, return partial results or a clear error message instead of hanging forever

Workaround

Currently, users can only recover by:

  1. Pressing Ctrl+C to interrupt
  2. Killing the Claude Code process directly

The session state is not recoverable after this occurs.

Impact

This is a significant usability issue because:

  • The background agent pattern is recommended by Claude Code for complex tasks
  • Complete session loss occurs with no warning
  • No data is returned from any of the agents' work
  • Users have no indication of what went wrong

Additional Context

  • This occurred during a workflow that spawned 4 specialized analysis agents
  • All agents were actively working (making API calls, running bash commands) when they stopped
  • The debug log shows activity until ~15 seconds after agent launch, then complete silence
  • No crashes, OOM errors, or exceptions were logged - everything just stopped

View original on GitHub ↗

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