API 400 on paste-image-without-text: empty text block persists in transcript, breaks all subsequent turns

Resolved 💬 8 comments Opened Apr 18, 2026 by loungecrasher Closed Jun 5, 2026

Pasting image without accompanying text produces empty text block → API 400 on next turn

Summary

When the user pastes an image into Claude Code 2.1.x without typing any accompanying text, the resulting user message's content array contains an image block followed by an empty text block ({"type":"text","text":""}). The message sends successfully the first time, but every subsequent turn in that session re-sends the full transcript to the API, which rejects it with:

400: messages: text content blocks must be non-empty

(older variant on earlier paste-failures also produces: cache_control cannot be set for empty text blocks)

The session becomes unusable until the transcript JSONL file is manually repaired on disk.

Affected version

Claude Code 2.1.112 (current as of 2026-04-18). Likely all 2.1.x — bug observed since at least 2.1.90.

Reproduction

  1. Open any Claude Code session
  2. Paste an image (screenshot, copied file, etc.) into the prompt
  3. Hit enter WITHOUT typing any text
  4. (First turn may succeed)
  5. Send any further user message
  6. API rejects with 400 "text content blocks must be non-empty"

Evidence from our transcripts

After repairing two sessions, the corrupt blocks all matched this pattern:

{
  "role": "user",
  "content": [
    {"type": "image", "source": {...}},
    {"type": "image", "source": {...}},
    {"type": "text", "text": ""}    ← bug
  ]
}

Sometimes one image, sometimes 2+, always with a trailing empty text block.

Expected behavior

Either:

  • A: client strips the empty text block before adding to transcript (preferred)
  • B: client inserts a placeholder text block with minimal content (e.g., "(image attachment)")
  • C: API accepts empty text blocks on user messages when the array contains non-empty blocks

Impact / frequency

Single user, 10 agents on one host. Our most-paste-heavy agent hit this 8+ times in one day (running Sprint 14 review with screenshots). Each occurrence requires manual intervention on the JSONL file. We've built an auto-repair hook as a stopgap but the bug is in the client serialization, not the transcript.

Environment

  • macOS 15.x (Darwin 25.x)
  • Apple Silicon (M4)
  • Terminal.app and iTerm2 both affected
  • Codeman (web UI) sessions also affected

Workarounds currently in use

  1. Manual: always type at least one character alongside pasted images (easy to forget)
  2. Automated: UserPromptSubmit hook that scans the transcript for empty text blocks and strips them before each API call (working, but shouldn't be necessary)

Root-cause hypothesis

The paste handler likely always appends a trailing text block to the content array regardless of whether text was entered. If the text input is empty, the block is added with text: "" instead of being omitted.

Suggested fix

In the message serialization path, if the content array would end with an empty text block AND contains at least one non-text block before it, drop the empty text block before serialization.

View original on GitHub ↗

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