anthropics / anthropics/claude-agent-sdk-typescript
canUseTool control channel closes when main query emits result while background Task subagents still running (subagent tools fail with 'AbortError: Stream closed')
- Lingua principale
- Shell
- Stelle
- 1.8k
- Fork
- 226
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Descrizione
## Environment
- `@anthropic-ai/claude-agent-sdk` **0.3.211**
- Node **v22.22.0**
- Windows 11 Pro (10.0.26100)
- SDK embedded in a long-running Node server; sessions created via `query()` with a `canUseTool` callback and hooks (`SubagentStart`/`SubagentStop`, etc.)
## Summary
When the main query emits its `result` message while **background Task subagents are still running**, the permission control channel is torn down. Every subsequent permission-gated tool call made by those subagents fails with:
```
Tool permission request failed: AbortError: Stream closed
```
The subagents themselves keep running (their `SubagentStop` hooks and task notifications still arrive afterward), but they can no longer execute any tool that needs a `canUseTool` decision, so they can only fail or produce degraded output. The host application's `canUseTool` callback is never invoked for these calls — nothing is denied; the request simply has no channel to travel over.
## Reproduction scenario
1. Start a `query()` (streaming input mode) with a `canUseTool` callback that approves tool use.
2. Give the agent a prompt that makes it spawn several **parallel background Task subagents** and then end its turn to wait for them (e.g. "spawn four reviewer subagents, wait for their reports").
3. The main conversation loop finishes its turn → SDK emits `result`.
4. The still-running subagents' subsequent `Bash`/`Read`/etc. calls now fail with `Tool permission request failed: AbortError: Stream closed`.
## Evidence from captured sessions
We analyzed the persisted message logs of 6 affected sessions (an automated code-review pipeline that spawns 4 parallel reviewer subagents per session):
- **Every** `Stream closed` tool failure carries a `parent_tool_use_id` (i.e. is a subagent call); the main agent's own calls never fail this way. Example counts per session (subagent failures / main-agent failures): 10/0, 5/0, 6/0, 6/0, 18/0.
- The first failure consistently appears at the exact point the main agent ends its turn to wait for the subagents.
- The host's `canUseTool` callback is never invoked for the failing calls (no permission events emitted app-side).
- Subagent calls that do **not** require a permission round-trip (e.g. allowed CLI-side by settings rules) continue to succeed after the channel closes — confirming the subagent processes are alive and only the permission relay is gone.
- `system`/`task_notification` messages and `SubagentStop` hooks for those subagents still arrive minutes after the main `result`, on the same (still open) message stream.
## Expected behavior
The `canUseTool` control channel should remain usable as long as any subagent of the session is still running — or at minimum until the query stream itself is closed by the SDK consumer. Alternatively, `result` should not be emitted while background subagents hold pending work (or the docs should state that permission relaying ends at `result`).
## Impact
For autonomous/headless pipelines this is a hard failure mode: the main agent yields to wait for subagents, the session looks "complete" to the host, and the subagents silently lose the ability to run permission-gated tools. In our case review sessions burned ~$2 each across repeated retries without ever posting their output.
## Workaround
Passing the needed tools via `options.allowedTools` (so no `canUseTool` round-trip is required) makes subagents immune to the channel closure. Copying permission allowlist settings into the working directory achieves the same CLI-side.
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Valutazione
Questa issue non è ancora stata valutata.