Webview image paste/attach sets `media_type:"image/jpeg"` for HEIC bytes (extension-based sniff) — 400 + permanent history poisoning
Summary
When a HEIC image is attached to a chat in the Claude Code VS Code extension (here, running inside Google Antigravity 1.23.2), the extension serializes the request body with "media_type":"image/jpeg" while the data payload is raw HEIC bytes. Anthropic's API only accepts JPEG/PNG/GIF/WebP, so the request is rejected with 400 invalid_request_error: "Could not process image". Because the HEIC blob is stored in the conversation transcript, every subsequent turn — including text-only follow-ups with no new attachment — replays the bad payload to the API and fails identically. The chat is unrecoverable; there is no client-side affordance to remove a single message from history.
Same root pattern as #55338 (extension-based media_type detection) but on the webview attach path, not the Read tool. Same downstream symptom as #56016 and #24387 (history poisoning) but with a distinct root cause and trigger.
Environment
- Claude Code extension: 2.1.120 (
anthropic.claude-code-2.1.120-darwin-arm64) - Host IDE: Google Antigravity 1.23.2
- macOS 26.4.1 (25E253), Apple Silicon
Repro
- In any Antigravity / VS Code window with the Claude Code panel open, attach a HEIC file (e.g. an iPhone camera photo or anything pasted in via Universal Clipboard / AirDrop / Photos.app). The chip in the input box may render with a
.jpeglabel even when the source bytes are HEIC. - Send any prompt with the attachment.
- Observe:
API Error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"Could not process image"}, ...} - Send a follow-up message with no attachment. → Same 400. This will continue indefinitely until a new chat is started.
Evidence — actual outbound payload (from extension log)
File: ~/Library/Application Support/Antigravity/logs/<TS>/window1/exthost/Anthropic.claude-code/Claude VSCode.log
"type":"image","source":{"type":"base64","media_type":"image/jpeg",
"data":"AAAAIGZ0eXBoZWljAAAAAG1pZjFNaUhFbWlhZmhlaWM..." [+ ~1.5 MB more bytes]
Decoded base64 prefix:
00 00 00 20 66 74 79 70 68 65 69 63 → ftyp box, major brand "heic"
00 00 00 00 6D 69 66 31 4D 69 48 45 → compat brands: mif1, MiHE,
6D 69 61 66 68 65 69 63 miaf, heic
That is unambiguously an HEIF/HEIC ISO BMFF container, not a JPEG.
Failing request_ids from one session: req_011CaqH98rKLm4bSD3TomC4s, req_011CaqHFV4QvbeRvzYBd3DRC, req_011CaqHHzgSbYB39acYivzLk, req_011CaqHQHRviMkgjBnePVBcu, req_011CaqHQgaxGSwH4LDtugfZe, req_011CaqHTD4pdyErJivmp6jjE. The first four had a HEIC attachment; the last two had no attachment (history-replay failures).
Expected behavior
Either:
- Sniff magic bytes, not filename/extension, when setting
media_typeon attachments in the webview's send path. Fall back to client-side transcoding (HEIC → JPEG/PNG via e.g. Sharp / native APIs) before serialization, or - Reject unsupported formats at attach time with a user-visible error ("HEIC is not supported — convert to PNG/JPEG"), so a bad payload never reaches the API and never enters chat history.
Plus: when an API rejection of the active turn is due to image content, don't persist the failed user turn into the conversation history — it dooms every subsequent turn. (This is the cross-cutting fix tracked in #24387 / #56016.)
Workarounds
- Convert the HEIC before attaching:
sips -s format png input.heic --out output.png - Use ⌘⇧4 / ⌘⇧3 native macOS screenshots (always PNG)
- Avoid Universal Clipboard / AirDrop / Photos.app as the image source
- Once a chat is poisoned, start a new chat — there is no recovery path
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗