Read tool fails on every local image with 400: Could not process image

Resolved 💬 7 comments Opened May 19, 2026 by myronahn Closed Jun 25, 2026

Read tool fails on every local image with 400: Could not process image

Summary

In a Claude Code session, asking Claude to Read any local image file (PNG or JPEG, any encoding I tested) consistently triggers:

API Error: an image in the conversation could not be processed and was removed.

The underlying API response is:

400 {"type":"error","error":{"type":"invalid_request_error","message":"Could not process image"},"request_id":"req_..."}

This rejects every image regardless of format, bit depth, dimensions, or metadata. Pasted-in-chat images (drag-and-drop / screenshot paste) work fine in the same session — the failure is specific to the Read tool's image-attachment path.

Environment

  • Claude Code: 2.1.144
  • Model: Claude Opus 4.7 (1M context)claude-opus-4-7[1m]
  • OS: macOS 26.5 (Darwin 25.5.0, arm64)

Steps to reproduce

In any Claude Code session, ask Claude to Read any local image file. Example:

Read /tmp/handcrafted.png

Where /tmp/handcrafted.png is generated by this Python one-liner (no third-party deps required):

python3 - <<'PY'
import struct, zlib
W, H = 100, 60
raw = b''
for y in range(H):
    raw += b'\x00'  # filter: None
    for x in range(W):
        raw += bytes([x*255//W, y*255//H, 128])
def chunk(t, d):
    return struct.pack('>I', len(d)) + t + d + struct.pack('>I', zlib.crc32(t + d) & 0xffffffff)
sig = b'\x89PNG\r\n\x1a\n'
ihdr = struct.pack('>IIBBBBB', W, H, 8, 2, 0, 0, 0)  # 8-bit, color type 2 (RGB)
idat = zlib.compress(raw)
png = sig + chunk(b'IHDR', ihdr) + chunk(b'IDAT', idat) + chunk(b'IEND', b'')
open('/tmp/handcrafted.png', 'wb').write(png)
PY

The resulting file is a 100×60 8-bit RGB PNG with only the minimum required chunks (IHDR + IDAT + IEND). file reports: PNG image data, 100 x 60, 8-bit/color RGB, non-interlaced. MD5 0e13ecb0103964a6ad01973549425102.

What I ruled out

Each of the following PNGs/JPEGs was Read in the same session and rejected the same way:

| File | Format | Notes |
|---|---|---|
| 1×1 transparent PNG (hand-crafted bytes) | 8-bit RGBA | Tiny dimension |
| 400×200 white-bg with text | 16-bit grayscale (ImageMagick default) | Default magick output |
| 400×200, re-encoded as 8-bit RGBA | magick -depth 8 -type TrueColorAlpha PNG32: | Forced color depth |
| 400×200, 8-bit RGB, metadata stripped | magick -strip -define png:color-type=2 | No tEXt/tIME/bKGD chunks |
| 100×60 hand-crafted PNG | 8-bit RGB, IHDR + IDAT + IEND only | Minimum-chunk PNG |
| 100×60 JPEG | JFIF baseline 8-bit | JPEG of the same content |

So it's not:

  • bit depth (16-bit grayscale, 8-bit RGB, 8-bit RGBA all fail)
  • color type (grayscale, RGB, RGBA all fail)
  • metadata chunks (stripped and hand-crafted minimal PNGs fail)
  • dimensions in the trivial direction (1×1, 100×60, 400×200 all fail)
  • format (PNG and JPEG both fail)
  • ImageMagick-specific output (hand-crafted PNG fails too)

Expected behavior

Read of a valid image file attaches the image to Claude's context so it can be described/analyzed.

Actual behavior

Every Read of a local image file returns the "image in the conversation could not be processed and was removed" error. The 400 response from the Claude API suggests the Read tool is sending a payload the API rejects — most likely a content-type / encoding issue in how Read dispatches the image bytes rather than anything about the image itself.

Impact

For pipelines that rely on Read to inspect local images (e.g. a codification pipeline that asks Claude to corroborate a screenshot summary against the image file), the read-and-corroborate path is effectively broken right now. The workaround is to paste images into chat instead of using Read, but that breaks any automated flow.

Notes

Pasted-in-chat images (drag-and-drop / screenshot paste) work normally in the same session — only Read-attached images fail. This points the finger at the Read tool's image-dispatch path rather than at a model-side or account-side issue.

View original on GitHub ↗

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