[Bug] v2.1.109 / Opus 4.7 — silent stuck-turn during tool execution (two distinct failure modes)
[Bug] Claude Code v2.1.109 / Opus 4.7 — silent stuck-turn during tool execution (two distinct failure modes)
Summary
Running a long-lived interactive session via claude --channels plugin:telegram@claude-plugins-official under systemd, we hit the model in a permanently stuck state — stop_reason: tool_use but no follow-on activity. The session stops processing, no error is emitted, the process stays alive. Two distinct stuck flavors observed in a single day, both on the same agent doing the same task class.
Environment
- Claude Code CLI: v2.1.109
- Model: claude-opus-4-7 (1M context)
- Host: Ubuntu 24.04 on AWS EC2 t3.micro (1.9 GB RAM)
- Launched via:
script -qec "claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions --disallowedTools mcp__telegram-mcp__tg_send" /dev/nullunder systemdRestart=always - Working directory: a git repo with
CLAUDE.md,.mcp.json, a local.claude/skills/tree - Effort level:
CLAUDE_CODE_EFFORT_LEVEL=max - Auto-memory disabled:
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 - Auto-updater disabled:
DISABLE_AUTOUPDATER=1
Failure mode A — Edit tool_use with no tool_result
When: 2026-04-19 11:13:43 UTC
Session: 1a642596-ee80-4d9e-bf8a-eee474d4e82a
Last JSONL assistant entry:
{
"type": "tool_use",
"id": "toolu_01NeNUJdzhBeeckre3Zxm5TD",
"name": "Edit",
"input": {
"file_path": ".../skills/holder-scanner/scripts/scan_holders.sh",
"old_string": "<263 chars, ASCII-only, a bash variable block>",
"new_string": "<626 chars, ASCII-only, adds a sourced helper block>",
"replace_all": false
}
}
stop_reason: tool_use. No matching tool_result ever written to JSONL. File on disk untouched. Subsequent queue-operation enqueue entries from the TG plugin piled up but the session could not dispatch them (turn still open).
Preceding context: 14 tool calls (Bash, Grep, Read, Write chains) in the 90 seconds before the stuck Edit. No errors in any of those results.
Failure mode B — assistant never emits next message after a successful tool_result
When: 2026-04-19 09:36:29 UTC
Session: fc891dc4-a248-4d22-949e-3b061660c307
Last JSONL assistant entry:
{
"type": "tool_use",
"name": "Read",
"input": {
"file_path": ".../skills/holder-scanner/scripts/scan_holders.sh",
"offset": 1,
"limit": 40
}
}
This is different from mode A. The tool_result WAS written (file content returned normally). But the model never produced the next assistant message — no text, no further tool_use, no end_turn. The stop_reason of that last assistant entry was tool_use, meaning the model expected to continue the turn. It just... stopped.
All tool_use/tool_result IDs matched cleanly (60/60). The turn was not closed. JSONL stopped growing except for a single queue-operation enqueue 7 minutes later when the user's follow-up message arrived (also never dispatched).
Shared signature
Both sessions exhibited tool_use:end_turn stop ratios far outside the norm:
| Session | tool_use stops | end_turn stops | Ratio |
|---|---|---|---|
| fc891dc4 (mode B, 09:36) | 60 | 2 | 30.0 |
| 1a642596 (mode A, 11:13) | 32 | 1 | 32.0 |
| Baseline across 10 healthy sessions Apr 17-18 | — | — | 3.0 — 7.0 |
So the stuck-turn correlates with the model chaining unusually many tools before the hang. Both runs involved heavy compound work (committing coordinated code changes after a peer review, touching multiple files).
What we ruled out
- TG channel plugin is not involved — it only delivers inbound messages and handles the
replytool. The hang is upstream of message delivery, inside Claude Code's tool execution / turn generation. - bun subprocess was alive and healthy throughout both hangs.
- MCP configuration — we cycled between
ENABLE_TOOL_SEARCH=false(eager) and default (deferred), and between full.mcp.jsonand{"mcpServers": {}}. Both stuck-turns recurred across configurations. - Memory pressure — not at OOM; ~700 MB used of 1.9 GB. No OOM entries in dmesg/journal.
- Edit payload in mode A is a straightforward ASCII text replacement in a
.shfile, 626-char new_string,replace_all: false. Nothing unusual — no emoji, no regex specials, no huge size. - Disk state — project files fine, no I/O errors, the Edit never actually ran.
Request
- Is there telemetry / logging we can enable on the CLI to catch the handoff between model response and tool execution (mode A) and the handoff between tool_result and next model turn (mode B)?
- Is the 30x tool_use:end_turn ratio a known precursor to tool-execution hangs in v2.1.109 / Opus 4.7?
- Is there a way to surface the hang as an error (exit code, SIGTERM, or at least an error line in the JSONL) instead of silent freeze? Currently there's no signal from the CLI — the process stays running, the session stays "active," but no tool is executing and no assistant turn is advancing.
Happy to pull the full JSONLs and attach them to this issue if it helps. Both stuck sessions are preserved at:
/home/ubuntu/.claude/projects/-home-ubuntu-nolix/1a642596-ee80-4d9e-bf8a-eee474d4e82a.jsonl.stuck-20260419-edit1113/home/ubuntu/.claude/projects/-home-ubuntu-nolix/fc891dc4-a248-4d22-949e-3b061660c307.jsonl.stuck-20260419
9 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Update — same Edit payload succeeded in a different session (session-state-specific, not content-specific)
Follow-up to the two stuck-turns from earlier today. I reproduced the exact failure mode A Edit (
toolu_01NeNUJdzhBeeckre3Zxm5TD, 2026-04-19 11:13:43 UTC) from a different Claude Code session on a different machine:tool_result.scp'dscan_holders.shto my Windows box, opened a fresh Claude Code session, calledEditwith the exact samefile_path/old_string(263 chars) /new_string(626 chars) /replace_all: false.So the content of the Edit isn't the trigger — the same bytes behave fine in a fresh session on a different host. Whatever is wedging the tool execution is carried by the Nolix session's accumulated state (long turn history, channel-plugin queue, many MCP subagents, high tool-use:end_turn ratio — all present in the stuck session and absent in my fresh repro session).
A few more observations from the stuck session that may help narrow it:
stop_reason: tool_use. Both stuck-turn instances today were preceded by similar bursts with tool_use:end_turn ratios of 30-32:1 — ~4-10× our historical baseline of 3-7:1.tool_useentry withstop_reason: tool_useand nothing after. The channel plugin'squeue-operation enqueueentries for later user messages pile up in the JSONL because the turn is still "open" from Claude Code's perspective — model never got atool_resultto continue with, but also never got an error.fc891dc4-...) showed the variant where thetool_resultwas written (Read of the samescan_holders.shrange) but the model never produced the next assistant message.stop_reason: tool_useon the preceding assistant, 60tool_usestops vs 2end_turnin that session. Same family of "model wedged mid-turn in a long tool chain," different point of wedge.claude -p/--channels, no journald entry. The only observable recovery path issystemctl restart.Best-guess hypothesis: under some condition reachable by long sessions with many MCP tools + long tool chains, the bridge between model-side tool_use emission and tool_execution / tool_result plumbing drops a message. No user-visible error, no retry, no timeout — the turn just stays half-open forever. A timeout + exit-on-stall would turn this silent hang into a loud failure we could at least auto-recover from.
Happy to share the full JSONLs privately if useful. Both stuck sessions preserved at:
/home/ubuntu/.claude/projects/-home-ubuntu-nolix/1a642596-ee80-4d9e-bf8a-eee474d4e82a.jsonl.stuck-20260419-edit1113/home/ubuntu/.claude/projects/-home-ubuntu-nolix/fc891dc4-a248-4d22-949e-3b061660c307.jsonl.stuck-20260419Response to the duplicate-check bot + new data point
Re: the three flagged candidates — they describe the same cluster of bugs but each captures only one facet:
tool_result) = our failure mode B. Specific toSkilltool; ours sees the same pattern afterRead.tool_resultdelivered) = our failure mode A, but forBash. Ours isEdit.This issue is not a duplicate of any one — it's an umbrella/upgrade with material new evidence:
Editpayload that hung the long-running agent session succeeded instantly in a fresh Claude Code session on a different host. None of #47996/#35773/#44596 have that A/B evidence.Editwith 263→626-char ASCII replacementEditon the same file with 317→5480-char new_string containing non-ASCII box-drawing chars (─ ═ ║)New data point — Hang #3 (failure mode A recurrence 2 hours after the first two)
6276dfc2-7fff-4a98-96f8-e81e725a40fa(the session that started after we restarted to recover from Hang #2)Edit, idtoolu_012MGe1GuMdGZZhzk3hRX6M4scan_holders.shtool_uselogged at 2026-04-19T12:12:14Z,stop_reason: tool_usetool_resultever written; JSONL frozen for 5 min before systemd restart# ──────...)new_string(5480 chars) + non-ASCIIPreserved at:
/home/ubuntu/.claude/projects/-home-ubuntu-nolix/6276dfc2-7fff-4a98-96f8-e81e725a40fa.jsonl.stuck-20260419-edit1212Asks
systemctl restartis the only recovery path — no exit code, noexit_reason, no stderr from the CLI.👎'ing the auto-close comment to prevent the 3-day auto-closure.
Important correction — the affected agent was running v2.1.109, not latest
Shortly after my last comment I noticed the hanging agent (Nolix) was pinned to v2.1.109 (Apr 15 release) via
DISABLE_AUTOUPDATER=1in its systemd unit — a policy chosen months ago to prevent restart cycles after the npm→native migration.Which means it has been running 3 versions behind for 3 days and has not received the v2.1.113 fix:
…which reads exactly like our symptoms, plus the native-binary refactor in v2.1.113 that likely touches the tool-execution plumbing we were staring at.
I've upgraded the agent to v2.1.114 (install via
claude install latest, symlink swapped, service restarted clean). Post-upgrade smoke test is healthy — bun subprocess alive, channel plugin serving, first interactive turn completed without orphanedtool_use. Going to run this agent on a deliberately heavy compound Edit workload next and report back.Two outcomes possible:
DISABLE_AUTOUPDATERpolicy. My session that reproduced A/B "successfully" was running on the Windows 2.1.114 build — which would have actually been silently exercising the same post-fix code path. That's still a useful data point for anyone on frozen older builds.Downgrading the severity of my earlier claim until the post-upgrade test run completes. Apologies for the initial "upstream bug" framing — when the version drift turned up, that framing got weaker than the evidence supports. Leaving the issue open for the test result.
Also worth flagging for triage: the fact that
DISABLE_AUTOUPDATER=1is documented in a fair number of long-lived-agent setups (ours, plus other community patterns we've seen) and silently freezes users on the old stream-hang code path is itself a product observation — worth a callout in theDISABLE_AUTOUPDATERdocs that it does NOT just disable the updater prompt, it actually freezes you at the install-time version until you manuallyclaude install latest. Easy to miss.Closing — post-upgrade test passes, issue was version drift
15-min stress test on the upgraded agent (v2.1.114):
unmatched=1briefly, all cleared within 60-90s as the tool_result came back — matches the v2.1.113 "stalled streams abort after 5 min" behavior)unmatched=1stayed frozen indefinitely, requiredsystemctl restarteach timeClosing this as duplicate of whatever the v2.1.110–v2.1.113 fixes resolved internally. All three candidates the bot flagged (#47996, #35773, #44596) are also likely manifestations of pre-v2.1.113 stream-hang; worth noting that those reporters were all on 2.1.106–2.1.107 era.
Takeaway:
DISABLE_AUTOUPDATER=1silently froze the agent 3 versions behind the fix. If the Claude Code docs could add a one-liner toDISABLE_AUTOUPDATERexplaining that users must manuallyclaude install lateston a schedule (the env var doesn't queue updates, it just disables the prompt), that'd help long-lived-agent operators avoid this exact rabbit hole.Mitigation shipped on our side: nightly version-check cron that flags outdated CLI in the agent's daily Telegram recap. Available as a pattern for anyone running similar setups.
Thanks for the triage — closing. If we see a recurrence on v2.1.114 I'll file fresh with clean JSONLs rather than resurrect this thread.
Closing — post-upgrade test passes. See final comment.
Filed #51927 as a focused follow-up on the surviving Mode A failure mode. Mode B appears fixed post-v2.1.113; Mode A persists across v2.1.114/2.1.116/2.1.117 on headless sessions with new diagnostic signatures and tested workarounds. Keeping discussion of the surviving mode there.
same problem here even opus 46
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.