Session freezes indefinitely when multiple background agents + blocking TaskOutput
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
- Launch 4 background agents using the
Tasktool withrun_in_background: true - Have the main session call
TaskOutputwithblock: trueandtimeout: 60000on all 4 agents - 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
- Race condition in TaskOutput blocking logic: TaskOutput may be waiting on a condition that will never be satisfied when agents die unexpectedly
- No heartbeat/liveness check for agents: TaskOutput doesn't detect that agents have stopped producing output to their log files
- Concurrent API connection limit: 5 simultaneous API sessions may exceed some internal or API-side limit, causing all streams to fail silently
- Missing error propagation: When agent streams fail with
stop_reason: null, this error state isn't propagated to TaskOutput
- Timeout not implemented correctly: The
timeoutparameter on TaskOutput appears to have no effect when agents are in a broken state
Suggested Fixes
- 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
- Add stream health monitoring: Detect when streams have
stop_reason: nulland treat as an error condition
- Limit concurrent agent API calls: Queue agent requests or implement backpressure to prevent overwhelming the API
- Improve timeout handling: Ensure TaskOutput timeout actually fires even when the underlying agent is in an inconsistent state
- 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:
- Pressing Ctrl+C to interrupt
- 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
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗