canUseTool callback not invoked for background subagent tool calls in default permission mode

Resolved 💬 11 comments Opened Feb 20, 2026 by nicolasnoble Closed May 24, 2026

Summary

When using the Claude Agent SDK with a custom canUseTool callback in default permission mode, background subagents spawned via the Task tool (run_in_background: true) do not route tool permission requests through the callback. The SDK denies their tool calls internally without ever invoking canUseTool. Additionally, these internal denials can corrupt the parent session's transport, causing subsequent main-agent tool calls to fail with "Stream closed".

This bug affects default mode specifically. In bypassPermissions mode, everything works correctly. Reproduced with both personal accounts (with bypassPermissions access) and corporate accounts (without), confirming the bug is in default mode handling.

Environment

  • Claude Agent SDK: 0.2.42 (bundled with Claude Code 2.1.42)
  • Platform: Linux (Debian)

Reproduction

A standalone reproduction case is available at: https://github.com/nicolasnoble/claude-sdk-bug-report

git clone https://github.com/nicolasnoble/claude-sdk-bug-report
cd claude-sdk-bug-report
npm install
npx tsx repro.ts
# For non-default credential locations:
CLAUDE_CONFIG_DIR=~/.claude-work npx tsx repro.ts

The script starts a session in default mode with a canUseTool callback that auto-allows all tools and logs every invocation. It triggers Claude to spawn a background subagent that runs a simple Bash command, then reports whether canUseTool was invoked.

Expected output

[canUseTool] canUseTool called: Task (agentID=main, ...)
[canUseTool] canUseTool called: Bash (agentID=main, ...)
[canUseTool] canUseTool called: Bash (agentID=<subagent-id>, ...)

Subagent calls (1+):
  canUseTool called: Bash (agentID=<subagent-id>, ...)

OK: canUseTool was called for subagent Bash calls.

Actual output

[canUseTool] canUseTool called: Task (agentID=main, ...)
[canUseTool] canUseTool called: Bash (agentID=main, ...)

Subagent calls (0):
  BUG CONFIRMED: canUseTool was never called for subagent tool uses.

The subagent reports "Permission to use Bash has been denied" without canUseTool ever being invoked.

Additional observations

  • bypassPermissions mode works correctly: subagent tool calls are properly handled. The bug is specific to default mode.
  • Silent permission mode downgrade: requesting bypassPermissions on an account without access silently falls back to default with no error or warning. The only way to discover this is by inspecting the permissionMode field on the system/init message.
  • Transport corruption: after background subagent permission denials, subsequent main-agent Bash calls fail with "Tool permission request failed: Error: Stream closed". The transport self-heals after several minutes.
  • Background subagents are isolated from all permission mechanisms: we tested all three available approaches and none reach background subagents:
  • canUseTool callback: never invoked for background subagent tool calls
  • allowedTools in query options: does not propagate to background subagents
  • Bash(*) in user-level settings (the same settings file the session uses, confirmed via CLAUDE_CONFIG_DIR): does not propagate to background subagents
  • The canUseTool type definition includes agentID?: string for subagent identification, suggesting the callback is designed to handle subagent tool calls.

Bugs

  1. canUseTool not called for background subagents in default mode: the SDK denies tool calls internally without invoking the callback. Background subagents appear completely isolated from all three permission mechanisms.
  2. Transport corruption: internal subagent denials break the parent session's transport ("Stream closed"), requiring several minutes to self-heal.
  3. Silent permission mode downgrade: no error or warning when bypassPermissions is unavailable - the SDK silently falls back to default.

View original on GitHub ↗

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