Intermittent silent stalls mid-turn, no error/timeout — reproduces cross-backend (native API + DeepInfra), related to #40462
Claude Code CLI: intermittent silent stalls, no error, no timeout — cross-backend reproduction
Summary
Claude Code CLI intermittently stalls mid-turn with no error, no crash, and no visible timeout. The status line keeps showing an active "thinking"/tool-status indicator, but nothing happens for anywhere from several minutes to (in the original case) over 13 hours. When it eventually resolves, the output is correct and complete — as if nothing went wrong. This closely matches issue #40462 ("Claude silently stalls mid-session — sending another message kicks it back to life"), but with additional evidence this report adds: the stall reproduces across multiple backends (native Anthropic API and third-party OpenAI/Anthropic-compatible routing via DeepInfra), across unrelated projects, and even in a completely clean config directory with no custom settings, hooks, or history.
Environment
- macOS (Apple Silicon, M3 Max)
- Claude Code CLI, reproduced on multiple versions including the current 2.1.233
- Both tmux-hosted long-running sessions and plain interactive terminal sessions
- Both native Anthropic API backend and DeepInfra-routed backend (via
ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKENoverride to a Chat-Completions-compatible third-party host)
Core symptom
- Session appears to be actively "thinking" or running a tool (status line stays live), but produces no output and no error for an extended period.
- No crash, no exception, no rate-limit message, no network error surfaced anywhere.
- Eventually resolves on its own with a fully correct, complete response.
- Recurs intermittently — not on every turn, but frequently enough to be a serious practical problem for long-running or automated sessions.
- Has been observed for weeks, across many CLI versions.
Concrete reproductions
- Original case: a Sonnet-backed session (native Anthropic API), executing step 1 of a 5-step plan (adding OpenTelemetry instrumentation to an internal framework), took 13+ hours to complete that single step. In the same window, equivalent work completed normally via Claude Desktop and Codex.
- Isolated bash-call stall: a session showed "Composing…" for 9+ minutes on a bash command (
lsof+ severalcurlcalls, each with an explicit--max-timeof 2–3 seconds). The command itself has a hard ceiling of roughly 10–15 seconds even in the worst case, which rules out the shell subprocess as the bottleneck — the delay was somewhere in the model/client turn-handling itself. - Post-update reproduction: after updating to the current CLI version and restarting the session fresh (no
--resume, ~5% context), the identical class of task stalled for 20m10s — longer than a pre-update baseline of 10m16s on the same task. Ruled out a large/stale context or prompt-cache invalidation as the cause, since a freshly started session with minimal context stalled longer, not shorter. - Cross-project reproduction: a completely unrelated project/session (no shared config, hooks, or
CLAUDE.md) exhibited the same delays. - Clean-environment reproduction: running with
CLAUDE_CONFIG_DIRpointed at an empty directory — fresh login, zero saved settings, zero hooks, zero customCLAUDE.md— still stalled on the same simple task (3m8s+ observed before resolving). - Cross-backend reproduction (DeepInfra): a session routed to DeepSeek V4 Flash via DeepInfra was asked to inspect and summarize a small codebase. The final answer was accurate and complete, but the full turn took 40m37s. DeepInfra's own usage dashboard for that period shows only 1,536 output tokens generated for that model that day — at any reasonable inference speed that's well under two minutes of actual generation. The remaining ~38 minutes were not spent generating anything, which points at the client's own turn-handling/streaming pipeline rather than model latency, network conditions, or the specific backend.
What's been ruled out
- MCP server/tunnel unavailability — other tools (Desktop, Codex) hit the same MCP servers heavily during a stall window without issue.
- Human-approval/permission gate — sessions were actively monitored (including Discord-based alerting) throughout; no prompt went unanswered. The documented "kick" workaround from #40462 (sending new input to the stalled session) was tested directly and did not reliably resolve the stall.
- A local process leak — a genuine, separate leak was found and fixed in unrelated custom MCP infrastructure (an internal whiteboard filesystem MCP server); the CLI stall persisted identically after the fix.
- CLI version — reproduces on the current version (2.1.233) exactly as on older versions.
- The built-in streaming idle watchdog (default 5-minute abort/retry on a fully idle stream) — a stalled run passed the 5-minute mark with no visible abort or retry, ruling this out as the mechanism that eventually ends the stall.
- A specific file read — a
Read()call on a small (~3.5 KB, 52-line), unmodified-in-weeks memory file appeared adjacent to several stalls; directly checked and ruled out (trivial size, no lock, no concurrent writer). - Session context size / prompt-cache invalidation — reproduces (and was in one case worse) on a fresh session at ~5% context.
- Account-level rate limiting/throttling — reproduces at the very start of a usage window as well as near its cap; Claude Desktop, Cowork, and Projects on the same account never exhibit this behavior under the same conditions.
- Project-specific configuration (
CLAUDE.md, hooks,.mcp.json) — reproduces in an unrelated project and in a fully clean config directory with none of this present.
Relationship to #40462
This report's symptoms match #40462 closely: no error, no timeout, intermittent, present across many versions for a long time. This report adds:
- Confirmation that the stall reproduces on a non-Anthropic backend (DeepInfra), not just the native Anthropic API — narrowing the cause toward the CLI's own client-side turn/streaming handling rather than anything specific to Anthropic's infrastructure.
- Token-count evidence (via the backend provider's own billing dashboard) directly showing that generation itself was fast and the delay occurred after or around actual model output — not during it.
- That the "send a new message to kick it loose" workaround described in #40462 did not reliably work in this case, suggesting there may be more than one underlying mechanism producing similar symptoms, or that the kick is not universally effective.
Suggested next steps for maintainers
- Given the DeepInfra reproduction, worth checking whether the delay correlates with a specific tool call, event, or SSE frame that the client fails to process/render promptly — the token-count evidence suggests the response may already exist server-side well before the CLI displays it.
- A repro harness that logs raw SSE/stream events with timestamps alongside the CLI's own turn-completion event would help distinguish "server never sent it" from "client received it but didn't process it."
Appendix: raw transcript excerpts
These are pasted directly from the sessions described above, unedited.
A. Bash-call stall with a hard time ceiling (~9 minutes on a command with a 10–15s max possible runtime)
❯ should I be able to access localhost 3101-3?
⏺ Running 1 shell command
⎿ $ lsof -nP -iTCP:3101,3102,3103 -sTCP:LISTEN 2>/dev/null
echo ---
curl -s -o /dev/null -w "3101: %{http_code}\n" http://localhost:3101/ --max-time 3
curl -s -o /dev/null -w "3102: %{http_code}\n" http://localhost:3102/ --max-time 3
curl -s -o /dev/null -w "3103: %{http_code}\n" http://localhost:310…
✽ Composing… (9m 0s · ↓ 372 tokens)
B. Same command, on a freshly updated CLI binary and freshly restarted session (no --resume), eventually completing at 10m16s with a fully correct answer
Yes — all three should be reachable from your machine, with different scopes:
- :3101 (whiteboard MCP, filesystem server via supergateway) — bound to 127.0.0.1 only...
- :3102 (state-server MCP) — also 127.0.0.1-only, same 401...
- :3103 (state-server REST + dashboard) — bound to 0.0.0.0... GET / returns 200...
✻ Sautéed for 10m 16s
C. Clean-environment reproduction (CLAUDE_CONFIG_DIR pointed at an empty directory, fresh login, zero saved config) — 20m10s, longer than the pre-update baseline above
peet@Profix claude-infra % should I be able to access localhost 3101-3?
⏺ Bash(lsof -nP -iTCP:3101-3103 -sTCP:LISTEN 2>&1; echo "---"; lsof -nP -iTCP -sTCP:LISTEN 2>&1 | grep -E ':310[0-9]')
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 64080 peet 12u IPv4 ... 0t0 TCP 127.0.0.1:3101 (LISTEN)
node 99589 peet 16u IPv4 ... 0t0 TCP 127.0.0.1:3102 (LISTEN)
node 99589 peet 17u IPv4 ... 0t0 TCP *:3103 (LISTEN)
---
port 3101: http status: 401
port 3102: http status: 401
port 3103: http status: 200
⏺ Read(/Users/peet/.claude/projects/-Users-peet-Development-claude-infra/memory/project_infra_state.md)
Yes — all three are up and listening locally: [... correct, complete explanation ...]
✳ Brewed for 20m 10s
D. Cross-backend reproduction (DeepInfra / DeepSeek V4 Flash, via a Claude Code CLI session with ANTHROPIC_BASE_URL pointed at DeepInfra) — 40m37s for the full turn
❯ Please inspect the code base and tell me what it is.
Thought for 3s
Let me explore the codebase to understand what it is.
Thought for 9s, called whiteboard 7 times
PhasorSeq — What It Is
PhasorSeq is a VCV Rack plugin — a virtual Eurorack module for the VCV Rack
(https://vcvrack.com/) modular synthesizer platform. Built by Peet van Tooren
(kurkesmurfer) under the brand Towering Inferno, licensed GPL-3.0.
[... full correct, detailed module description, code structure table, and
DSP logic breakdown omitted for length — output was accurate and complete ...]
✻ Crunched for 40m 37s
DeepInfra's own billing dashboard for deepseek-ai/DeepSeek-V4-Flash that day shows:
| Type | Usage |
|---|---|
| in tokens | 130,213 |
| out tokens | 1,536 |
| cached in tokens | 278,784 |
1,536 output tokens is consistent with the length of the delivered answer, and would take well under two minutes to generate at any normal inference speed — accounting for only a small fraction of the 40m37s the turn actually took.