Repository navigation
Description
Description
When a tool result adds image content (e.g. a screenshot returned by an MCP tool, or reading an image file) to a session whose model only accepts text input, every subsequent request fails with HTTP 400 from the provider. OpenCode surfaces the upstream error verbatim with no way to locate or remove the offending message, leaving the session permanently unusable with that model.
Example error, replayed on every turn:
upstream returned HTTP 400: {"object":"error","message":"Model only supports text input; received unsupported content type 'image_url'.","type":"BadRequestError","param":null,"code":400}
The provider config used (redacted):
{
"model": "nio_ds/glm-5.3",
"providers": {
"nio_ds": {
"package": "aisdk:@ai-sdk/openai-compatible",
"settings": { "baseURL": "https://<internal-gateway>/openai/v1", "apiKey": "<redacted>" },
"models": {
"glm-5.3": {
"name": "DS-GLM-5.3",
"limit": { "context": 1048576, "output": 65536 }
}
}
}
}
}Expected behavior:
- When
capabilities.input: ["text"]is declared for a model (or once the provider has rejected image content), image parts should be stripped or replaced with a text placeholder when assembling requests, so the session stays usable. -
- At minimum, when a provider rejects a request because of image content, the error should identify the offending message and offer a recovery path (remove the message, revert to an earlier turn, or retry without image content).
Additional context: the root trigger is the uncatalogued-model default of assuming image input support ("These are fallback assumptions, not detected capabilities" per the V2 models docs). With private OpenAI-compatible gateways this assumption is frequently wrong, and a single tool result then breaks the session.
- At minimum, when a provider rejects a request because of image content, the error should identify the offending message and offer a recovery path (remove the message, revert to an earlier turn, or retry without image content).
Workarounds:
- Declaring
"capabilities": { "tools": true, "input": ["text"], "output": ["text"] }on the model prevents new sessions from hitting this (whether it also repairs an already-affected session by filtering the stored history on send has not been verified). -
- Switching the affected session to a multimodal model (
<leader>m) restores it; a compact under that model, then switching back, also unblocks the original model.
- Switching the affected session to a multimodal model (
-
-
<leader>uundo back to before the image-producing turn also works, at the cost of losing later turns.
-
Plugins
superpowers (git+https://github.com/obra/superpowers.git); MCP servers: playwright, chrome-devtools (local)
OpenCode version
2.0.27
Steps to reproduce
- Configure a custom OpenAI-compatible provider whose model only accepts text input and is not in models.dev (e.g. a private gateway). Because the model is uncatalogued, OpenCode falls back to assuming text and image input.
-
- Start a session with that model and an MCP server that returns screenshots (e.g. playwright
get-screenshot).
- Start a session with that model and an MCP server that returns screenshots (e.g. playwright
-
- Invoke the screenshot tool. The image enters session history as tool-result content.
-
- The next model request fails:
upstream returned HTTP 400: ... "Model only supports text input; received unsupported content type 'image_url'".
- The next model request fails:
-
- Every subsequent turn replays the same history, including the image, and fails identically. The session is permanently unusable with this model.
Screenshot and/or share link
No response
Operating System
macOS 15 (Darwin 24.6.0, darwin arm64)
Terminal
iTerm.app (TERM=xterm-256color, COLORTERM=truecolor), shell: /bin/zsh
Activity
opencode-agent commentedon Oct 13, 2026
Thanks for the detailed report! I think this is a duplicate of #52042.
In v2, images from tool results and pasted attachments go through the same check before each request (
unsupportedPartsinpackages/core/src/session/model-request.ts). That check replaces any image the model can't accept with a short text note. It only does this when the model'scapabilities.inputleaves outimage. A custom model with no declared capabilities defaults toinput: ["text", "image"], so the image is sent and the provider rejects it on every turn. #52042 reports this same root cause and also asks for a clearer error and a way to recover. The only difference is that its image was pasted, while yours came from a tool result.Possible duplicates and related issues, ordered by likelihood:
On your unverified workaround: that check runs over the whole stored history on every request. So declaring
"capabilities": { "input": ["text"], "output": ["text"] }on the model should also fix a session that's already affected, not just new ones. Stored images get replaced with anERROR: Cannot read …note when the request is sent.The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
opencode-agent commentedon Oct 14, 2026
Closing this as a duplicate of #52042, since we haven't heard back. Both are the same v2 problem: a custom model with no declared capabilities defaults to accepting image input, so images get sent and the provider returns 400 on every turn. Please follow #52042 for progress.
Until that's resolved, declaring
"capabilities": { "input": ["text"], "output": ["text"] }on the model should keep sessions usable. OpenCode should then replace stored images with a text note when it sends each request.If your case turns out to be different, reply here and we'll take another look. Thanks again for the detailed report!