claude -p hangs permanently after mid-session MCP tool call returns fetch error
Summary
claude -p (v2.1.87) hangs permanently when an MCP tool call fails with "fetch failed" mid-session over the Streamable HTTP transport. The process stays alive (event loop runs, timers fire) but never makes another API call. The conversation is permanently stuck.
Reproduction
- Start
claude -pwith--mcp-configpointing to HTTP MCP servers - The model makes several successful MCP tool calls
- One MCP tool call fails with a transport-level error (
"fetch failed"/ 502) - The error is recorded as
is_error: truein the conversation - Expected: Model receives the error and continues (makes next API call)
- Actual: Process hangs forever — no further API calls, no stdout output
Evidence
Observed across 3 concurrent claude -p processes (all v2.1.87, ARM64 Alpine container):
- Each process was actively working (making API calls, running MCP tools)
- Each hit a transient
"fetch failed"from an HTTP MCP server - Each went permanently silent after the error tool_result was recorded
- Processes remained alive for 30+ minutes: event loop running (
epoll_pwaitwith 1s timeout), ~3 context switches/sec, 91-95 MB RSS - Zero TCP connections after the hang — no API calls being attempted
.claude/projects/-app/{sessionId}.jsonlshows conversation ends at the error tool_result
Process state during hang
- Main thread:
epoll_pwait(syscall 22) on eventpoll fd, 1000ms timeout - I/O thread:
epoll_pwaitwith infinite timeout - 8 worker threads:
futex(idle) - 0 TCP sockets open (verified via
/proc/{pid}/fd/) - Voluntary context switches increasing at ~3/sec (timer wakeups only)
Conversation log pattern (from .jsonl)
assistant: tool_use cortex_synapse_search(...) ← succeeds
user: tool_result [results]
assistant: tool_use cortex_synapse_search(...) ← parallel call
user: tool_result "fetch failed" (is_error: true)
← HANGS HERE, no more entries
Key distinction
- Clean failure at init (MCP server not reachable when session starts): Handled gracefully — model notes "server not connected" and adapts
- Dirty failure mid-session (MCP server was connected, some calls succeeded, then one fails): Process hangs permanently
Reproduction test
Running the exact same command (claude -p + same prompt + same --mcp-config + same --model claude-opus-4-6 + same --allowedTools) immediately after the hang succeeds in 2-5 seconds. The issue is triggered by transient MCP transport failures, not persistent misconfiguration.
Environment
- Claude Code: 2.1.87
- Platform: Linux aarch64 (Alpine, Docker container)
- MCP transport: Streamable HTTP (
"type": "http"in mcp-config) - Model: claude-opus-4-6 (also observed with sonnet)
- Auth: OAuth token (
CLAUDE_CODE_OAUTH_TOKEN)
Impact
In automated/headless environments (CI, job queues), these hung processes consume pool slots indefinitely. The only recovery is external kill + resubmit. Safety-net timeouts (e.g., 4 hours) are the only failsafe, which is far too slow for interactive job systems.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗