Repository navigation
bug: tool-result media 400s whole request for models without attachment capability #41163
Description
Activity
This issue might be a duplicate of existing issues. Please check:
- GLM-5.2 session broken when model foolishly tries to view a screenshot #34113: Same symptom — GLM-5.2 via LiteLLM, screenshot from a tool result poisons the session context; every subsequent turn returns the same image-input rejection error.
If these issues are distinct (e.g. the root cause or fix path differs), feel free to clarify and we can keep both open.
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:
level=ERROR message="stream error" providerID=kimi-for-coding modelID=k3 error.error="AI_APICallError: Invalid request Error"
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
imageblock: 200 - 200 byte PDF as a
documentblock: 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").
Problem
supportsMediaInToolResultinmessage-v2.tsreturnstrueunconditionally for@ai-sdk/anthropicand@ai-sdk/openainpm packages. For models withattachment: 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 whereunsupportedParts()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'sattachmentcapability is false — regardless of the SDK npm package.Environment
attachment: falseserved via@ai-sdk/anthropicor@ai-sdk/openai