Repository navigation
Description
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
Activity
github-actions commentedon Jan 11, 2026
Found 3 possible duplicate issues:
stop_reasonnot parsed frommessage_deltawhen usingANTHROPIC_BASE_URLproxy #16785This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
aaaaaandrew commentedon Jan 13, 2026
Reopening: This is NOT a duplicate of #14124 (SQLite lock)
After extensive process-level debugging, I can confirm this is a different bug from the SQLite lock contention issue. The symptoms are similar (session freeze) but the root cause is distinct.
Diagnostic Evidence
Process sampling of frozen Claude Code session shows:
If this were the SQLite issue (#14124), the main thread would show
__ulock_wait2on SQLite operations, not__read_nocancel.Key Differences from SQLite Issue #14124
__ulock_wait2(lock acquisition)__read_nocancel(pipe/socket read)journal_mode=DELETE+busy_timeout=0PRAGMA journal_mode=WALI have applied the SQLite WAL workaround and confirmed it does NOT fix this issue.
Reproduction Scenarios
This freeze occurs in multiple scenarios:
Scenario A: Multiple background agents
run_in_background: trueScenario B: Single skill invocation (NEW FINDING)
->(none))Scenario B proves the bug is not solely about "too many parallel agents" - it can happen on simple operations.
Process State When Frozen
Diagnostic One-Liner
To differentiate this bug from SQLite #14124:
Environment
Suggested Root Cause
The main thread appears to be blocked on a synchronous read from a pipe or unix socket. In an event-driven runtime like Bun, synchronous blocking reads should not occur on the main thread. Possible causes:
The Bun Pool worker threads are blocked on
__ulock_wait2, likely waiting for the main thread to release a lock or complete an operation - classic deadlock pattern.Request
Please investigate the IPC/pipe handling in the Task tool and MCP communication paths. The
__read_nocancelblocking point suggests a missing async wrapper or incorrect blocking call on the main thread.This is a critical bug that makes Claude Code unusable for workflows involving skills, agents, or MCP tools.
aaaaaandrew commentedon Jan 13, 2026
Workaround Confirmed: Avoid Task Tool / Subagents Entirely
After testing, I can confirm that avoiding the Task tool completely prevents the freeze.
What Works
Running all analysis sequentially on the main thread using direct Bash/Read/Grep tool calls instead of spawning subagents via Task tool.
What Doesn't Work
run_in_background: falsestill freezesWorkaround
For skills/workflows that previously used Task tool with subagents:
Taskfromallowed-tools/tmp/files as checkpoints in case of crashThis is a significant limitation as subagents are useful for:
But until this bug is fixed, avoiding Task tool entirely is the only reliable workaround.
Exception
Subagents may still be useful for queries with very large responses (e.g., Glean search results) where you want a subagent to summarize before returning to main thread. Use at your own risk - the freeze is non-deterministic.
aaaaaandrew commentedon Feb 1, 2026
Additional Pattern Observed: AWS CLI / Lambda Correlation
After further investigation and more occurrences of this freeze, I've noticed a pattern that may help narrow down the root cause:
The freeze often occurs when running commands that make AWS API calls - specifically:
aws lambda invoke,aws s3, etc.)Observations
Hypothesis
This may be related to or compounded by:
The IPC deadlock I identified earlier (
__read_nocancelon main thread) could be triggered when:Debug Data Point
When frozen during AWS command execution:
__read_nocancel(pipe/socket read)stop_reason: null(incomplete response)Happy to collect more diagnostic data if there are specific things that would help.
github-actions commentedon Mar 2, 2026
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
github-actions commentedon Mar 10, 2026
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.