Skip to content

Session freezes indefinitely when multiple background agents + blocking TaskOutput #17540

Closed as not planned

Description

@aaaaaandrew

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

  2. No heartbeat/liveness check for agents: TaskOutput doesn't detect that agents have stopped producing output to their log files

  3. Concurrent API connection limit: 5 simultaneous API sessions may exceed some internal or API-side limit, causing all streams to fail silently

  4. Missing error propagation: When agent streams fail with stop_reason: null, this error state isn't propagated to TaskOutput

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

  2. Add stream health monitoring: Detect when streams have stop_reason: null and treat as an error condition

  3. Limit concurrent agent API calls: Queue agent requests or implement backpressure to prevent overwhelming the API

  4. Improve timeout handling: Ensure TaskOutput timeout actually fires even when the underlying agent is in an inconsistent state

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

Activity

  1. github-actions commented on Jan 11, 2026

    @github-actions

    Found 3 possible duplicate issues:

    1. [BUG] Parallel subagent execution freezes due to SQLite lock contention in __store.db #14124
    2. [BUG] stop_reason not parsed from message_delta when using ANTHROPIC_BASE_URL proxy #16785
    3. [Bug] Context window exhaustion causes multi-agent freeze #15892

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. aaaaaandrew commented on Jan 13, 2026

    @aaaaaandrew
    Author

    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:

    Main thread:     __read_nocancel   (blocked on pipe/socket read syscall)
    Bun Pool 0-4:    __ulock_wait2     (waiting for internal lock)
    File Watcher:    kevent            (normal - waiting for events)
    HTTP Client:     kevent64          (normal - waiting for events)
    

    If this were the SQLite issue (#14124), the main thread would show __ulock_wait2 on SQLite operations, not __read_nocancel.


    Key Differences from SQLite Issue #14124

    Aspect SQLite Issue (#14124) This Issue
    Main thread blocked on __ulock_wait2 (lock acquisition) __read_nocancel (pipe/socket read)
    Root cause SQLite journal_mode=DELETE + busy_timeout=0 IPC deadlock in event loop
    Workaround PRAGMA journal_mode=WAL None available
    Triggers 3+ parallel SQLite writers Skill invocation, background agents

    I 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

    1. Spawn 4+ background agents via Task tool with run_in_background: true
    2. Call TaskOutput on them
    3. Session freezes indefinitely

    Scenario B: Single skill invocation (NEW FINDING)

    1. Invoke a skill that uses Task tool or MCP tools
    2. Session freezes before any agents even spawn
    3. No zombie children present
    4. All unix sockets still connected (not ->(none))

    Scenario B proves the bug is not solely about "too many parallel agents" - it can happen on simple operations.


    Process State When Frozen

    $ ps -o pid,ppid,state,args
    <PID> <PPID> S+   claude
    
    $ ps -o pid,ppid,state,args | awk '$2==<PID>'
    <MCP1> <PID> S+   npm exec @upstash/context7-mcp
    <MCP2> <PID> S+   npm exec mcp-remote https://mcp.atlassian.com/v1/sse
    # No zombie children in Scenario B
    
    $ lsof -p <PID> | grep unix
    # All sockets show ->0x... (connected), NOT ->(none)
    
    $ sample <PID> 1 | grep -E "read_nocancel|ulock"
    __read_nocancel  (in libsystem_kernel.dylib)        883
    __ulock_wait2    (in libsystem_kernel.dylib)       4415
    

    Diagnostic One-Liner

    To differentiate this bug from SQLite #14124:

    sample <frozen-pid> 1 -f /tmp/s.txt && grep -E "main-thread" -A 60 /tmp/s.txt | grep -oE "(read_nocancel|ulock_wait)" | head -1
    # "read_nocancel" = THIS bug (IPC deadlock)
    # "ulock_wait" on main thread path = SQLite bug (#14124)

    Environment

    • Claude Code: 2.1.4 (Homebrew cask)
    • Platform: macOS Darwin 25.2.0 (arm64)
    • MCP servers: context7, atlassian (via mcp-remote SSE)

    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:

    1. Blocking IPC call - Main thread waiting for response from child/MCP that never arrives
    2. Event loop starvation - Something preventing the event loop from processing I/O completion
    3. FD inheritance issue - Pipe write-end inherited by grandchild, preventing EOF on read

    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_nocancel blocking 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.

  3. aaaaaandrew commented on Jan 13, 2026

    @aaaaaandrew
    Author

    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

    • Spawning even 1-2 subagents can trigger the freeze
    • Wave patterns (batching agents) still freeze
    • run_in_background: false still freezes
    • The freeze happens during Task tool invocation, not just with parallel agents

    Workaround

    For skills/workflows that previously used Task tool with subagents:

    1. Remove Task from allowed-tools
    2. Replace agent spawning with direct inline execution (Bash, Read, Grep, etc.)
    3. Save progress to /tmp/ files as checkpoints in case of crash

    This is a significant limitation as subagents are useful for:

    • Keeping context window clean
    • Parallel execution
    • Specialized agent prompts

    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.

  4. aaaaaandrew commented on Feb 1, 2026

    @aaaaaandrew
    Author

    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 CLI commands (aws lambda invoke, aws s3, etc.)
    • Commands that invoke Lambda functions returning large responses (1000+ lines)

    Observations

    1. Large output correlation: Freezes more likely when tool output exceeds ~30KB (crosses the persisted-output threshold)
    2. Network-dependent: AWS API calls involve HTTPS connections that can experience TCP stalls
    3. Intermittent: Same command sequence sometimes works, sometimes freezes - suggests timing/network conditions matter
    4. Fresh session workaround: Exiting and starting a new session often (but not always) allows the same operation to succeed

    Hypothesis

    This may be related to or compounded by:

    The IPC deadlock I identified earlier (__read_nocancel on main thread) could be triggered when:

    1. A Bash command makes an external API call
    2. The response is large enough to trigger persist-to-disk handling
    3. Some race condition in processing the persisted output blocks the main thread

    Debug Data Point

    When frozen during AWS command execution:

    • Main thread: blocked on __read_nocancel (pipe/socket read)
    • Model state: "thinking" spinner frozen, 0 tokens being generated
    • API stream: stop_reason: null (incomplete response)

    Happy to collect more diagnostic data if there are specific things that would help.

  5. github-actions commented on Mar 2, 2026

    @github-actions

    Closing for now — inactive for too long. Please open a new issue if this is still relevant.

  6. github-actions commented on Mar 10, 2026

    @github-actions

    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.

  7. locked as resolved and limited conversation to collaborators on Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions