Claude Code goes silent for 10+ minutes in status=requesting after a tool_result with is_error=true
Summary
When a tool call returns a tool_result with is_error: true, Claude Code transitions to system:status:requesting and then emits no further stream-json output for at least 10 minutes — until the parent process eventually kills it. From the outside (a host MCP integration watching the stream-json output) there is no way to distinguish "agent is taking a long time to think" from "agent is wedged retrying upstream forever".
This is independent of the underlying tool-call failure cause: it reproduces against MCP -32000 Connection closed, against a fast-failing tool that returns is_error: true cleanly, and (per local triage) against unrelated upstream Anthropic 500s. The common factor is is_error=true arriving as the latest tool result.
Environment
- Claude Code: shipped via
@anthropic-ai/claude-code, running as Paperclip'sclaude_localadapter (stdio + stream-json) - Platform: macOS Darwin 24.6.0 x86_64
- Reference Paperclip run id:
71a50276-3695-48f4-bc0e-6a97b4581151 - Production rate: 40 of 68
claude_localheartbeat failures in a 48h sample matched this signature (28 via OK-tool-result chain that later failed, 8 via MCP-32000, 4 via tool-sideis_error=true).
Reproduction
Any setup that produces a tool_result is_error=true in the stream should reproduce. From a real run:
00:35:21Z assistant tool_use mcp__context-mode__ctx_execute(...)
00:35:42Z user tool_result is_error=true content="MCP error -32000: Connection closed"
00:35:42Z system status=requesting
[no further stream events for ~10 minutes]
00:45:42Z parent process SIGTERM (Paperclip 10-min watchdog)
Why this matters for MCP hosts
Stream-json is the contract a host process uses to tell whether Claude Code is making progress. After status=requesting, the next expected stream event is one of:
assistant.message(Claude responding with text or another tool_use), or- a system error / status change, or
- a result terminal event
When none of those arrive — for ten minutes — every host integration that watches stream-json runs a watchdog timer and kills the process. The agent's actual state in that ten minutes (retrying upstream? hung on a single request? deadlocked? waiting on a slow API?) is invisible.
What I think is happening (best guess)
After receiving is_error=true, Claude Code probably issues a request to the Anthropic API to generate a recovery response. Either:
- That API call hangs / times out silently. No retry/timeout/error event is emitted to stream-json while this is happening. Recently saw an unrelated batch of these resolve after a Claude Code re-login (Anthropic auth refresh), so expired/stale auth tokens may be one path that lands here.
- The API responds with another tool_use that also fails, and Claude Code enters a tight retry loop without flushing intermediate state to stream-json.
Either path needs to surface something to the stream — even a periodic heartbeat — for host integrations to tell thinking from dead.
What I'd ask for
Pick one (or both):
- Periodic heartbeat in
requestingstate. Emit asystem:statusline every N seconds (5? 10?) while inrequesting, so hosts can tell the agent is alive even if the upstream API is slow. A simple{"type":"system","subtype":"status","status":"requesting","elapsed_ms":12345}would solve this. - Hard timeout on
requestingwith a stream event when fired. If a single Anthropic API call exceeds some configured budget (default 60s? 120s?), emit asystem:errororresultline and either retry visibly or surface a terminal failure to the stream.
Either change would let host integrations like Paperclip distinguish slow-but-alive from dead-and-needs-killing without the current 10-minute SIGTERM cliff.
Related
Filed alongside #47378 (the -32000 Connection closed family); the two often co-occur — the transport drop trips is_error=true, then this silent-requesting behaviour kicks in. They are distinct bugs though: this one reproduces against any is_error=true cause, not just MCP transport drops. Tracking on our side as pcli-8ms AC2.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗