claude-code - 💡(How to fix) Fix Opus 4.8 + dynamic tool loading (ToolSearch) re-modifies signed thinking blocks → "messages.N.content.M ... cannot be modified" 400 storm → strip-and-retry every turn

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

On Claude Code 2.1.156 with Opus 4.8 and extended thinking enabled, dynamic/on-demand tool loading (ToolSearch) appears to mutate already-signed thinking/redacted_thinking blocks in earlier assistant turns. The server rejects the request with a 400, Claude Code strips the signed blocks and retries — costing a full extra API round-trip on every subsequent turn once the session is "poisoned," which compounds into multi-minute first-byte stalls.

The 2.1.156 changelog notes a thinking-block fix for Opus 4.8; this appears to be an incomplete fix — the dynamic-tool-loading path still triggers it.

Error Message

  • Each one followed by: [WARN] [thinking] server rejected ... stripping signed blocks and retrying

Root Cause

On Claude Code 2.1.156 with Opus 4.8 and extended thinking enabled, dynamic/on-demand tool loading (ToolSearch) appears to mutate already-signed thinking/redacted_thinking blocks in earlier assistant turns. The server rejects the request with a 400, Claude Code strips the signed blocks and retries — costing a full extra API round-trip on every subsequent turn once the session is "poisoned," which compounds into multi-minute first-byte stalls.

The 2.1.156 changelog notes a thinking-block fix for Opus 4.8; this appears to be an incomplete fix — the dynamic-tool-loading path still triggers it.

Fix Action

Fix / Workaround

Workaround (confirmed effective)

Setting ENABLE_TOOL_SEARCH=false eliminates it entirely. Across two comparable long sessions on the same machine/model:

  • ToolSearch ON: 86 ... cannot be modified 400s + the strip-and-retry storm.
  • ToolSearch OFF: 0 such 400s across 145 API requests; no stripping signed blocks retries; Dynamic tool loading absent. (Residual ~15s server stalls remain but are ordinary 1M-context variance, not the compounding loop.)
RAW_BUFFERClick to expand / collapse

Summary

On Claude Code 2.1.156 with Opus 4.8 and extended thinking enabled, dynamic/on-demand tool loading (ToolSearch) appears to mutate already-signed thinking/redacted_thinking blocks in earlier assistant turns. The server rejects the request with a 400, Claude Code strips the signed blocks and retries — costing a full extra API round-trip on every subsequent turn once the session is "poisoned," which compounds into multi-minute first-byte stalls.

The 2.1.156 changelog notes a thinking-block fix for Opus 4.8; this appears to be an incomplete fix — the dynamic-tool-loading path still triggers it.

Environment

  • Claude Code 2.1.156
  • Model: Opus 4.8 (1M context)
  • Extended thinking: on
  • ENABLE_TOOL_SEARCH: unset (defaults to ON / optimistic)

Symptoms (from --debug log)

  • Repeated API 400s: 400 invalid_request_error: messages.N.content.M thinking/redacted_thinking blocks ... cannot be modified
  • Each one followed by: [WARN] [thinking] server rejected ... stripping signed blocks and retrying
  • The 400 consistently cites the same two historical assistant messages (large past turns), and the log line immediately preceding the first failure is Dynamic tool loading: found N discovered tools in message history.
  • Once it starts, every later turn re-sends and re-fails, doubling first-byte latency and cascading into 15–30s+ stalls (worst case observed: a single turn stalled ~4.5 minutes). One affected session logged ~126 stripping signed blocks retries.

Root-cause hypothesis

On-demand tool loading changes the available tool set mid-session, causing Claude Code to re-serialize prior messages; that perturbs their signed thinking-block signatures, which the server then rejects as modified.

Workaround (confirmed effective)

Setting ENABLE_TOOL_SEARCH=false eliminates it entirely. Across two comparable long sessions on the same machine/model:

  • ToolSearch ON: 86 ... cannot be modified 400s + the strip-and-retry storm.
  • ToolSearch OFF: 0 such 400s across 145 API requests; no stripping signed blocks retries; Dynamic tool loading absent. (Residual ~15s server stalls remain but are ordinary 1M-context variance, not the compounding loop.)

Impact (latency confirmed; cost is a hypothesis)

  • Latency: clearly the dominant, evidenced harm — an extra round-trip per turn, cascading to multi-minute stalls.
  • Token cost (hypothesis, not measured): the retry works by modifying historical message content (the signed blocks), which would break the prompt-cache breakpoint at that point — forcing the prefix up to the modified message to be re-read as uncached input on the retry and likely on subsequent turns. Since uncached input is far more expensive than a cache read, this could materially increase billed input cost / subscription-usage consumption on large-context sessions, even though the per-turn token count looks similar. (The rejected 400 attempts themselves should not be billed, since they fail validation before inference.) We could not quantify this from the --debug log, which carries timing but not cache/token fields — flagging it as a plausible secondary cost for triage.

Expected

Dynamic tool loading should not invalidate previously-signed thinking blocks. If the tool set must change mid-session, prior signed blocks should remain valid (or be handled without a strip-and-retry on every subsequent turn, and without breaking prompt-cache reuse).

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix Opus 4.8 + dynamic tool loading (ToolSearch) re-modifies signed thinking blocks → "messages.N.content.M ... cannot be modified" 400 storm → strip-and-retry every turn