Sub-agent API 401 (auth expired) is reported to parent agent as "Request interrupted by user for tool use"

Open 💬 3 comments Opened Jun 25, 2026 by arcavenai

Summary

When a sub-agent (launched via the Agent tool with a subagent_type) makes an API call that returns HTTP 401 because the user's auth token has expired, Claude Code reports the failure to the parent agent as [Request interrupted by user for tool use]. The actual authentication_failed / 401 error is hidden, and the parent agent has no way to distinguish a real user cancellation from an upstream auth failure.

Environment

  • Claude Code version: 2.1.191
  • Platform: macOS (Apple Silicon, Homebrew install)
  • Session ID (truncated for privacy): eca7fe60-...

Evidence

The sub-agent's session JSONL transcript contains the real synthetic assistant message (sensitive ids redacted):

{
  "type": "assistant",
  "model": "<synthetic>",
  "stop_reason": "stop_sequence",
  "error": "authentication_failed",
  "isApiErrorMessage": true,
  "apiErrorStatus": 401,
  "content": [{
    "type": "text",
    "text": "Please run /login · API Error: 401 The security token included in the request is expired"
  }]
}

Yet the parent agent's transcript for the same moment shows only:

[Request interrupted by user for tool use]

So the harness saw a synthetic assistant message with isApiErrorMessage: true, apiErrorStatus: 401, and error: "authentication_failed", but rewrote that into a user-interrupt wrapper before handing it to the parent. The parent never sees the auth-error class.

Reproduction

  1. Launch a long-running sub-agent via the Agent tool (e.g. one that runs many Bash/Read/Edit cycles over 5+ minutes — long enough that an auth token can plausibly expire mid-run).
  2. Wait for the user's auth token to expire mid-run (or simulate by revoking it).
  3. The next API call the sub-agent attempts fails with HTTP 401 (authentication_failed).
  4. Observe: the parent agent sees [Request interrupted by user for tool use] as the sub-agent's result and acts on it (typically: asks the user what to do, treats work as user-cancelled).
  5. Expected: the parent should see an explicit auth-expired / API-error class (not a user-cancel wrapper), so it can retry after /login, prompt the user to re-auth, or otherwise pick a correct recovery path.

Why this matters

  • Long-running multi-agent workflows become unreliable. Orchestrator -> specialist sub-agent patterns (e.g. per-story TDD delivery cycles) cannot distinguish an auth blip from a deliberate user stop.
  • Parent agents take the wrong recovery path. "User cancelled" -> ask the user for direction. "Auth expired" -> retry after /login. These are not interchangeable, and conflating them wastes turns and confuses the user.
  • Users are blamed for cancellations they didn't perform. The phrasing "Request interrupted by user" tells the model (and any human reading the transcript) that the user hit Esc. They didn't.
  • In-flight sub-agent work is silently dropped with no diagnostic trail. Committed work survives on disk; in-memory partial reports and uncommitted edits do not, and there is no signal to the parent that the loss happened for an auth reason rather than a deliberate one.
  • Post-hoc diagnosis requires manual forensics on the local jsonl transcripts. This is not a workflow most users will know to perform.

Suggested fix

  1. Surface API errors (401, 429, 5xx) verbatim to the parent agent with HTTP status code and original error message intact. The sub-agent transcript already carries apiErrorStatus, error (class), and isApiErrorMessage: true -- propagate these fields.
  2. Use a distinct error class -- e.g. auth_expired, rate_limited, api_error -- separate from user_interrupted. The current wrapper conflates the two failure modes into one string.
  3. (Stretch) Offer to resume the sub-agent automatically once auth recovers, preserving its in-progress tool-call queue. At minimum, give the parent enough signal to choose between "ask user" and "retry on auth recovery."

Workaround

None. The parent agent has no way to distinguish a real user cancel from an upstream auth failure from the surfaced signal alone. Inspecting the local session jsonl can identify the cause after the fact, but that requires the user to know to look.

Related

  • #12447 -- OAuth token expiration disrupts autonomous workflows (root condition: auth expires mid-run; this issue is about how that failure is reported to a parent agent, which #12447 doesn't cover).
  • #64177 -- Workflow counts API-errored subagents as "completed" (adjacent mis-accounting of sub-agent API errors; different surface and different misclassification, but same shape: parent's view of sub-agent outcome doesn't match what actually happened).
  • #62311 -- Distinguish an explicit user interrupt (Esc) from a message that merely arrived mid-turn (related but inverse: that issue is about distinguishing user-interrupt from queued-message; this issue is about distinguishing user-interrupt from auth-failure).
  • #25818 -- Orchestrator has no diagnostic context when subagent fails (same family of "parent receives degraded failure info"; closed as stale).

View original on GitHub ↗

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