Opus 4.8 extended thinking: Stop hook block re-entry corrupts thinking blocks → 400
Summary
When a Stop hook emits {"decision": "block", "reason": "..."} during an Opus 4.8 session with extended thinking enabled, Claude Code re-enters the conversation but corrupts the thinking/redacted_thinking blocks in the last assistant message before making the next API call. The API rejects with a 400.
Error
API Error: 400 messages.1.content.1: `thinking` or `redacted_thinking` blocks in
the latest assistant message cannot be modified. These blocks must remain as they
were in the original response.
Steps to reproduce
- Start a Claude Code session with Opus 4.8 (extended thinking enabled by default)
- Have any Stop hook registered that can emit
{"decision": "block", "reason": "..."}— e.g. a verify gate, a recommend-before-asking gate, or any custom Stop hook - Trigger the hook (e.g. end a turn with Claude claiming work is done without verification)
- Observe 400 on the re-entry API call
Expected behavior
CC preserves thinking/redacted_thinking blocks verbatim in the messages array when continuing after a Stop hook block decision, as required by the API contract.
Actual behavior
CC modifies the thinking block content (exact corruption mechanism unknown from hook-space; could be truncation, re-encoding, or type change) before passing the messages array to the API. The API rejects.
Workaround
Switch to a non-thinking model (e.g. Sonnet) for the session. Alternatively, suppress Stop hook block decisions when thinking blocks are present in the last assistant turn — but this silently disables all Stop hook safety checks for thinking-capable sessions, which is a significant behavioral loss.
Notes
dangerouslyDisableSandbox: truedoes not affect this — the corruption happens in CC's message-reconstruction logic, not the sandbox layer- The issue affects any Stop hook that emits a block decision; it is not specific to any particular gate or hook implementation
- Workaround guard added locally in our hook setup (
stop_gates.ts) to prevent the crash, but this suppresses all gate checks for thinking-block turns — not a real fix
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗