Tool call serialized as text (court<invoke>) with stop_reason=end_turn — model emits no executable tool_use, turn silently stalls (claude-opus-4-8)
Summary: Model intermittently emits a tool call as literal text inside a text block instead of a structured tool_use block, then ends the turn (stop_reason=end_turn). The harness has nothing to execute, so the turn stalls with no output and no error. User perceives it as "command didn't run." Became chronic in a long multi-resume session.
Signature: assistant message, stop_reason=end_turn, text content contains literal:
court
<invoke name="Bash">
<parameter name="command">…</parameter>
</invoke>
The leading token court (a corrupted function-call delimiter) precedes every leaked call.
Evidence (one session): 18 leaked calls, all preceded by court. First occurrence 2026-06-04 13:28 was cosmetic (text leak coexisted with a valid tool_use, sr=tool_use, executed fine). From 2026-06-05 05:31 it turned fatal: text-only + end_turn, 14 turns in a row failed (05:31→10:50). All 29 real tool_use blocks in that window got results — zero orphans → not an input/interrupt race.
Repro context: session length 1739 lines across 3 days (multiple resumes); short turns (1 text line + 1 command) on heavy/dirty context. Model: claude-opus-4-8.
Requested fix (harness-side): detect assistant turns with stop_reason=end_turn whose text contains <invoke name= / court<invoke / function_calls → don't surface as final answer; log + auto-retry with a system nudge "emit the tool call as a structured tool_use, not text." This converts ~14 dead turns into 1 retry and breaks the stall→user-types→stall loop.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗