Skip to content

API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"messages.71.content.8: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response."},"request_id":"req_011CUQZ6ttKtJbU8JQRYyizo"}

Extended thinking is on, and the assistant turn you are sending back is not the one you received. The API compared the thinking blocks in your last assistant message against what it produced and found a difference, so it rejected the whole array before running anything. That rules out the usual suspects immediately: no model ran, so this is not the model misbehaving; it is not your API key (401), not your credit balance, not capacity (529), and not a context-length problem — a full window says Prompt is too long instead. What it is telling you is that something between the response arriving and the next request leaving edited a block it was not allowed to edit.

Only the latest assistant message is frozen

Read the rule precisely, because the scope is the whole story: the latest assistant message. Earlier assistant turns are not covered. You may truncate history, drop old turns, or remove thinking blocks from turns further back without hitting this error. The single most recent assistant message is the one that has to go back exactly as it came out.

That produces an inverted intuition, and it is the reason this page exists. When a conversation gets expensive or gets stuck, the two instincts are “trim it” and “edit the last turn”. Trimming is the safe one here; editing the last turn is the forbidden one. Most stuck-history problems are solved by surgically fixing the newest message and keeping everything else — this one specifically forecloses that move, which is why tools ship a rewind command rather than an edit-history command.

The index in the message is worth a second of attention too. messages.71 is the position of the message the API is treating as latest, and content.8 is the block inside it. If your history has messages after index 71, then what your client actually sent is not what you think it sent — that discrepancy is a finding in itself, and usually means a middleware layer is reshaping the array.

The rest of what this being a 400 invalid_request_error implies — no inference ran, nothing was charged for output, the failure is deterministic — is the shared behavior of the whole family, set out on the request-body parse failure page.

Is retrying useful?

No. The array is fixed the moment your client writes it, and an identical array fails identically.

The official SDKs retry connection errors, rate limits and 5xx responses with exponential backoff and leave 400 alone deliberately. There is no capacity or timing element here — a comparison between two byte sequences does not come out differently on the second attempt.

Retry once for the confirmation if you want it; a second identical failure proves the failure is deterministic and everything below applies. Then stop, and exclude 400 from any retry loop you wrote yourself. Also cross off two things that resemble retrying: switching models cannot help, because validation runs before a model is chosen, and /compact cannot help, because compaction is itself an API call built from the same broken history.

What counts as modifying a block

“Modified” is stricter than “meaningfully changed”. The comparison is against the original response, so anything that alters bytes counts — including changes you would never describe as edits. Each of these has a test attached.

  • You strip thinking blocks to save tokens or to clean up logs. The most common cause, and the most reasonable-sounding: thinking content is verbose and removing it looks like free savings. It is free on every turn except the newest. Test: your code has a filter over content blocks that runs on the outgoing history.
  • You edited the last assistant turn to repair a different error. Deleting a dangling tool_use block, or reordering blocks so the tool call comes first, changes the message that contains the thinking blocks. Test: this error appeared while you were hand-fixing another 400.
  • A proxy, gateway or SDK wrapper re-serialized the body. Re-encoding, key reordering, normalizing escapes, or truncating long strings for logging. Test: the identical request succeeds when sent directly and fails through the gateway. This is the fastest single test in the list — run it before reading your own code.
  • Automatic compaction or summarization rewrote the end of the history. If the rewrite reaches the most recent assistant turn, its thinking blocks are no longer originals. Test: the first failure follows a compaction or summarization step with no editing of your own in between.
  • Two processes are writing the same transcript. The same session open in two windows, or a sync tool merging the file. Test: check whether the session was resumed in more than one place, or lives on a synced drive.
  • You dropped the signature or other fields attached to the block. A thinking block is not just its text; it is the object the API returned. Keeping the prose and discarding the rest is a modification. Test: compare the block you are sending against the raw response object, field by field, not by eyeballing the text.

Repairs, by what rewrote the turn

  • Your own filter — scope it. Strip thinking blocks from every assistant message except the last one, and pass that one through untouched. That keeps almost all of the savings, because there is only ever one latest turn.
  • You edited the last turn to fix something else — stop editing and rewind instead. Go back to a checkpoint before the assistant turn that is causing trouble, so the offending message leaves the history entirely rather than being repaired in place.
  • A gateway is re-encoding — pass the assistant content through verbatim. If the gateway cannot be made byte-transparent, the practical fallback is to not use extended thinking through it, because every turn is a coin flip on whether the re-encoding happened to be lossless.
  • Compaction touched it — start a fresh session and restate the task; the rewritten turn cannot be un-rewritten. Where a tool exposes compaction settings, the relevant question is whether the summarization boundary can be kept away from the most recent turn.
  • Two writers — close the other instance first. Repairing the file while something else is writing it produces a fix that lasts until the next write.
  • You want to turn thinking off and move on — that stops new blocks from being produced, but it does not repair a history that already contains them. Your client still replays the stored assistant turn. Turning the feature off and continuing the same conversation is the fix that looks like it worked and did not.

Confirming the assistant turn round-trips

“It worked once” is weak evidence here, because a turn that happens not to include a modified block passes for reasons unrelated to your fix.

Send a turn that carries the full history and triggers no tools: a plain question. If it returns normally, the latest assistant message validated intact. Then do the thing that broke it — run the filter, go through the gateway, fire a tool — and check again. The decisive test for a filtering bug is stronger and cheap to run: take the raw assistant response object your client received, take the assistant message your client is about to send, and compare them programmatically. Equal means fixed; “looks the same” means untested.

If the 400 instead names tool use concurrency and tells you to run /rewind, a tool_use block is missing its result — and that page is where you will land if you try to fix it by deleting the dangling block, because deleting it trips the rule above. The validator’s own wording for the same break, Did not find 1 tool_result block(s) at the beginning of this message, carries a message index that tells you how far back to rewind. If the model emitted a tool call that could not be parsed, your history is intact — the damage is confined to one turn rather than baked into the array. That is a better position to be in, but it does not mean pressing enter again will help: by the time that message names a failed retry, the cheap attempt has already been spent. And if the complaint is an empty text block rather than a modified thinking block, you are looking at the opposite failure of the same replay mechanism. The AI coding error triage tool sorts them by whether your stored history is still valid, which is the question that decides whether you rewind or keep working.