You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug: tool-result media 400s whole request for models without attachment capability #41163
supportsMediaInToolResult in message-v2.ts returns true unconditionally for @ai-sdk/anthropic and @ai-sdk/openai npm packages. For models with attachment: false (no vision — e.g. GLM-5.2 served through an Anthropic-compatible endpoint), image/PDF attachments from tool results stay inside the tool result and are re-sent on every subsequent turn as part of history replay. The provider then rejects the entire request with a 400 (e.g. Model ... does not appear to support image inputs.), killing the response.
User-visible symptom: a session where a tool returned a screenshot works fine until a later turn — then every response dies with Bad Request: Model ... does not appear to support image inputs., even when the user sends only text.
Why this is a regression: with @ai-sdk/openai-compatible, media was extracted to a user message where unsupportedParts() converted it to a graceful text note ("ERROR: Cannot read image ... Inform the user.") and the model replied normally.
Expected behavior
Media from tool results should be extracted to a user message (degraded gracefully by unsupportedParts()) when the model's attachment capability is false — regardless of the SDK npm package.
Environment
opencode version: 1.18.14+ (reproducible on dev)
Model: any with attachment: false served via @ai-sdk/anthropic or @ai-sdk/openai
Not a duplicate of #34113 in my case, and I hit this today on a different provider.
Setup: opencode 1.18.15, provider kimi-for-coding (https://api.kimi.com/coding/v1, npm @ai-sdk/anthropic), model k3, which models.dev lists as attachment: false.
What happens: read on a PDF stores the file as state.attachments[0].url = data:application/pdf;base64,... inside the tool part (4.9 MB in my case). The tool output itself is just PDF read successfully. From the next turn on, every request 400s at step 0:
The session is then permanently dead. Retry, continue, a text-only prompt, all fail in about two seconds. Four sessions died this way before I traced it.
Isolated it with curl against the same endpoint and key:
text only: 200
1x1 PNG as an image block: 200
200 byte PDF as a document block: 400, {"error":{"type":"invalid_request_error","message":"Invalid request Error"},"type":"error"}
So it is not size, not the context limit, and not the subscription tier. The endpoint rejects document blocks outright, and a single PDF read poisons the history for good.
One caveat on the proposed fix: gating purely on attachment: false would also strip images that k3 does accept, per the PNG probe above. The check likely needs to be per format, input.pdf vs input.image, which is what #21908 was getting at.
Recovery for anyone stuck: the payload sits in ~/.local/share/opencode/opencode.db, table part, at json_extract(data,'$.state.attachments'). Find the row with data like '%data:application/pdf;base64%', remove that key, and the session streams again. I replaced it with pdftotext -layout output so the session kept the document content instead of losing it.
Confirmed on latest release 1.18.25 (2026-08-28), provider kimi-for-coding, model k3 (attachment: false via models.dev).
Repro: agent generated a 608 KB PDF via headless Chrome, then called read on it. Tool output was just "PDF read successfully", but the tool part stored attachments[0].url = data:application/pdf;base64,... From the next turn on, every request fails with AI_APICallError 400 "Invalid request Error".
Beyond the capability-check bug itself, the recovery UX is a dead end:
retry / "continue" re-send the poisoned history → same 400;
/compact also requires a model call with the same history → same 400;
UI revert only offers user messages as restore points, so a mid-session tool part cannot be removed without reverting the entire session.
The only recovery was manual surgery on opencode.db: deleting the read tool-part and the trailing error messages. Consider (a) degrading tool-result media to a text note for attachment:false models, and (b) a way to drop a poisonous part without a model call (e.g. "retry without this attachment").
V2 checks tool-result attachments against the model's supported input formats before sending each request. Unsupported images or PDFs become a text explanation instead of being replayed as media, regardless of the provider SDK. To get v2: npm i -g @opencode/cli@latest or curl -fsSL https://opencode.ai/v2/install | bash (desktop: update the app). If you still see this on v2, please open a new issue with the details.
Activity
github-actions commentedon Aug 8, 2026
This issue might be a duplicate of existing issues. Please check:
If these issues are distinct (e.g. the root cause or fix path differs), feel free to clarify and we can keep both open.
eenlars commentedon Aug 8, 2026
Not a duplicate of #34113 in my case, and I hit this today on a different provider.
Setup: opencode 1.18.15, provider
kimi-for-coding(https://api.kimi.com/coding/v1, npm@ai-sdk/anthropic), modelk3, which models.dev lists asattachment: false.What happens:
readon a PDF stores the file asstate.attachments[0].url = data:application/pdf;base64,...inside the tool part (4.9 MB in my case). The tool output itself is justPDF read successfully. From the next turn on, every request 400s at step 0:The session is then permanently dead. Retry, continue, a text-only prompt, all fail in about two seconds. Four sessions died this way before I traced it.
Isolated it with curl against the same endpoint and key:
imageblock: 200documentblock: 400,{"error":{"type":"invalid_request_error","message":"Invalid request Error"},"type":"error"}So it is not size, not the context limit, and not the subscription tier. The endpoint rejects
documentblocks outright, and a single PDF read poisons the history for good.One caveat on the proposed fix: gating purely on
attachment: falsewould also strip images that k3 does accept, per the PNG probe above. The check likely needs to be per format,input.pdfvsinput.image, which is what #21908 was getting at.Recovery for anyone stuck: the payload sits in
~/.local/share/opencode/opencode.db, tablepart, atjson_extract(data,'$.state.attachments'). Find the row withdata like '%data:application/pdf;base64%', remove that key, and the session streams again. I replaced it withpdftotext -layoutoutput so the session kept the document content instead of losing it.vokasug commentedon Aug 29, 2026
Confirmed on latest release 1.18.25 (2026-08-28), provider kimi-for-coding, model k3 (attachment: false via models.dev).
Repro: agent generated a 608 KB PDF via headless Chrome, then called
readon it. Tool output was just "PDF read successfully", but the tool part storedattachments[0].url = data:application/pdf;base64,...From the next turn on, every request fails withAI_APICallError400 "Invalid request Error".Beyond the capability-check bug itself, the recovery UX is a dead end:
The only recovery was manual surgery on
opencode.db: deleting the read tool-part and the trailing error messages. Consider (a) degrading tool-result media to a text note for attachment:false models, and (b) a way to drop a poisonous part without a model call (e.g. "retry without this attachment").neriousy commentedon Oct 19, 2026
V2 checks tool-result attachments against the model's supported input formats before sending each request. Unsupported images or PDFs become a text explanation instead of being replayed as media, regardless of the provider SDK. To get v2:
npm i -g @opencode/cli@latestorcurl -fsSL https://opencode.ai/v2/install | bash(desktop: update the app). If you still see this on v2, please open a new issue with the details.