API 400: harness emits content block with type: "fallback" — session becomes permanently unrecoverable

Open 💬 4 comments Opened Jun 10, 2026 by dennisgregory-lab

Summary

Claude Code emitted a request whose message content array contained a content block with type: "fallback", which is not a valid Anthropic API content-block type. The API returned 400 and the session became permanently unusable — every retry replays the same message array and fails at the same index.

Error (verbatim)

API Error: 400 messages.69.content.0: Input tag 'fallback' found using 'type' does not match any of the expected tags: 'advisor_tool_result', 'bash_code_execution_tool_result', 'code_execution_tool_result', 'connector_text', 'container_upload', 'document', 'image', 'mid_conv_system', 'redacted_thinking', 'search_result', 'server_tool_use', 'text', 'text_editor_code_execution_tool_result', 'thinking', 'tool_result', 'tool_search_tool_result', 'tool_use', 'web_fetch_tool_result', 'web_search_tool_result'

Environment

  • Model: claude-opus-4-7 (1M context variant)
  • Claude Code version: 2.1.170
  • OS: Linux 6.17.13-4-pve x86_64 (Debian Bookworm slim in Docker)

What I think is happening

"fallback" looks like an internal placeholder the harness inserts when it cannot reconstruct an original content block — e.g., a deferred tool result, a partial thinking block, or a block carried over from a different harness/SDK version during compaction. That placeholder is supposed to be rewritten into a valid type (tool_result, text, redacted_thinking, etc.) before the request goes out. In this case it wasn't, and it leaked into the wire payload.

Impact

The failure is terminal for the affected session. The bad block is baked into the on-disk transcript at index 69; every subsequent turn re-serializes the same array and hits the same 400 at the same index. Retrying or /clear-ing without --fork-session do not help. The only recovery is to abandon the session or fork it (and forking only helps if the fork serializer re-derives blocks rather than copying them through).

Repro

Unknown — I don't know what triggered the original fallback insertion. Likely candidates worth checking on your side:

  • A tool_use whose tool_result never arrived (timeout, cancel, harness restart mid-turn).
  • A thinking / redacted_thinking block from an older session resumed under a newer harness version.
  • A compaction pass that couldn't summarize a block and stubbed it.

Suggested fix

Whatever produces type: "fallback" should either (a) rewrite to a valid type before serialization, or (b) drop the block (with a text breadcrumb) rather than ship it. As a defensive measure, the pre-request serializer could assert against the API's content-block enum and refuse to send.

Asks

  1. Confirm whether --fork-session re-derives content blocks or copies them through.
  2. Is there a supported way to surgically remove a single bad block from an on-disk session transcript? Right now the only option is "abandon the session."

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗