Description
If the agent calls read on a .png file whose first bytes are not a PNG signature, the tool still reports Image read successfully and attaches the whole file as data:image/png;base64,.... The attachment is stored in the session and replayed on every following request, so the provider rejects every message from then on:
Error from provider (Console): Upstream request failed: [invalid_request_error] invalid image data at input[34].output[1]: the `image/png` payload could not be decoded (it may be corrupt or truncated).
There is no way to recover from inside OpenCode: new prompts, /compact attempts and plugin continuations all fail with the same error, because the tool result with the bad attachment is always included.
Root cause (unchanged on dev @ 193de13):
How it happened for real: adb exec-out screencap -p > shot.png on a multi-display Android phone writes a text warning ([Warning] Multiple displays were found, but no display id was specified! ..., 347 bytes) to stdout before the PNG bytes. file shot.png says data, but read happily attached it as image/png.
Expected: when the sniffed bytes don't match an image/PDF signature, don't attach the file as media (return an error like "file is not a valid PNG", or fall back to the text/binary path). Ideally also a recovery path: when a provider rejects a tool-result media part (400 invalid image), strip that attachment from history instead of failing forever. Related: #47487 (session bricked by image count, no recovery), #41163 (tool-result media 400s whole request).
Workaround that worked: clear state.attachments of that tool part in ~/.local/share/opencode/opencode.db (part table); the same session then works again.
Plugins
oh-my-opencode 4.19.4
OpenCode version
1.14.17 (code path verified identical on dev 193de13, 2026-09-10)
Steps to reproduce
- Make a "png" that is text followed by a real PNG:
printf '[Warning] Multiple displays were found, but no display id was specified!\n' > bad.png
cat some-valid.png >> bad.png
file bad.png # -> "data" (not a PNG)
- In OpenCode (any provider that accepts images; here provider
opencode, model muse-spark-1.3-contributor-free), ask the agent to read bad.png. Tool output: Image read successfully, with an image/png attachment.
- Send any next message. Provider returns 400
invalid image data ... could not be decoded.
- Every further message in that session fails identically (the attachment is replayed from the session DB each time).
Screenshot and/or share link
No share link (session contains personal screenshots). The provider error text above is copied verbatim from the log (service=llm ... error=AI_APICallError ... statusCode 400).
Operating System
macOS 26.6.2 (Darwin 25.6.0, arm64)
Terminal
ghostty
Description
If the agent calls
readon a.pngfile whose first bytes are not a PNG signature, the tool still reportsImage read successfullyand attaches the whole file asdata:image/png;base64,.... The attachment is stored in the session and replayed on every following request, so the provider rejects every message from then on:There is no way to recover from inside OpenCode: new prompts,
/compactattempts and plugin continuations all fail with the same error, because the tool result with the bad attachment is always included.Root cause (unchanged on
dev@ 193de13):sniffAttachmentMime()returns the extension-based fallback when no magic bytes match: https://github.com/anomalyco/opencode/blob/193de13a88/packages/opencode/src/util/media.ts#L15-L26readthen treats that mime as an image and attaches the raw bytes without checking they are decodable: https://github.com/anomalyco/opencode/blob/193de13a88/packages/opencode/src/tool/read.ts#L303-L325How it happened for real:
adb exec-out screencap -p > shot.pngon a multi-display Android phone writes a text warning ([Warning] Multiple displays were found, but no display id was specified! ..., 347 bytes) to stdout before the PNG bytes.file shot.pngsaysdata, butreadhappily attached it asimage/png.Expected: when the sniffed bytes don't match an image/PDF signature, don't attach the file as media (return an error like "file is not a valid PNG", or fall back to the text/binary path). Ideally also a recovery path: when a provider rejects a tool-result media part (400 invalid image), strip that attachment from history instead of failing forever. Related: #47487 (session bricked by image count, no recovery), #41163 (tool-result media 400s whole request).
Workaround that worked: clear
state.attachmentsof that tool part in~/.local/share/opencode/opencode.db(parttable); the same session then works again.Plugins
oh-my-opencode 4.19.4
OpenCode version
1.14.17 (code path verified identical on
dev193de13, 2026-09-10)Steps to reproduce
opencode, modelmuse-spark-1.3-contributor-free), ask the agent toread bad.png. Tool output:Image read successfully, with animage/pngattachment.invalid image data ... could not be decoded.Screenshot and/or share link
No share link (session contains personal screenshots). The provider error text above is copied verbatim from the log (
service=llm ... error=AI_APICallError ... statusCode 400).Operating System
macOS 26.6.2 (Darwin 25.6.0, arm64)
Terminal
ghostty