Read tool sends WebP images with incorrect media type (image/png), causing unrecoverable API 400 error

Resolved 💬 3 comments Opened Mar 26, 2026 by cwdx Closed Mar 29, 2026

Bug Description

When Claude Code encounters image data (via Read tool, Bash output, or head/cat of a file containing base64-encoded images), it auto-detects the image and sends it to the Anthropic API. However, it incorrectly identifies the media type for non-PNG formats, and in some cases sends data the API cannot process at all. This causes unrecoverable 400 errors that brick the entire conversation.

Two Distinct Error Scenarios Observed

Scenario 1: Data URI with WebP base64 (e.g., data:image/webp;base64,...)

When a file contains a data:image/webp;base64,... string (common for canvas-drawn signatures stored in databases), Claude Code detects it as image data and attempts to send it. The API responds:

API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
  "message":"Could not process image"},
  "request_id":"req_011CZR12rRFwwSDVKgMp5ARp"}

This happened when running head -c 40 on a file containing a WebP data URI from a PostgreSQL query.

Scenario 2: Raw WebP binary/base64 with wrong media type

When the image data reaches the API tagged as image/png but the actual content is WebP:

API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
  "message":"messages.3.content.14.image.source.base64.data: Image does not match the provided media type image/png"},
  "request_id":"req_011CZR1FrLQoLzAtrJqR1dvE"}

Steps to Reproduce

  1. Query a database for a field containing data:image/webp;base64,... (e.g., a signature canvas export)
  2. Save the result to a file: agio psql -t -A -f query.sql > /tmp/sig.txt
  3. Run any command that reads the file: head -c 40 /tmp/sig.txt or use the Read tool
  4. Claude Code detects image data → shows [Image data detected and sent to Claude]
  5. API returns 400 error

Critical: Unrecoverable Error

Once triggered, the conversation is permanently broken:

  • The malformed image content block is embedded in the message history
  • Every subsequent API call re-sends the entire message history including the broken image
  • Even completely unrelated prompts like "hello" or "continue" trigger the same 400 error
  • The user must abandon the session and start a new conversation
  • All conversation context (potentially hours of debugging work) is lost

In our case, this killed a 154K-token debugging session.

Expected Behavior

  1. Claude Code should sniff the actual image format from magic bytes/data URI before sending
  2. Set the correct media_type (image/webp, image/png, image/jpeg, image/gif)
  3. If the format is unsupported or unrecognizable, do not send it as an image — pass it as text or skip it
  4. Critical: If the API rejects an image, Claude Code should strip the failed image content block from the message history so the conversation can continue

Actual Behavior

  • Defaults to image/png regardless of actual format
  • Does not handle data: URI prefixed content correctly
  • On API rejection, the broken image persists in message history forever
  • No recovery mechanism exists

Suggested Fixes

Fix 1: Correct media type detection

Sniff format from magic bytes or data URI prefix:

  • PNG: \x89PNG / base64 iVBOR / data:image/png
  • JPEG: \xFF\xD8\xFF / base64 /9j/ / data:image/jpeg
  • WebP: RIFF....WEBP / base64 UklGR / data:image/webp
  • GIF: GIF89a / base64 R0lG / data:image/gif

Fix 2: Graceful fallback

If format detection fails or the API rejects the image, strip the image content block from the conversation and show a text note like [Image could not be displayed: unsupported format] so the conversation can continue.

Fix 3: Recovery mechanism

If any API call returns a 400 related to image content, automatically retry the call with the offending image block removed or replaced with a placeholder.

Workaround

Process the image externally before reading it:

# Convert WebP to PNG with sharp, then read the PNG
node -e "require('sharp')(Buffer.from(fs.readFileSync('/tmp/sig.txt','utf8').replace(/^data:image\/\w+;base64,/,''), 'base64')).png().toFile('/tmp/sig.png')"

Environment

  • Claude Code CLI v2.1.84
  • macOS Darwin 25.2.0
  • Model: claude-opus-4-6 (1M context)

View original on GitHub ↗

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