Repository navigation
Description
what happens
a session becomes permanently wedged when its message history contains image parts and the selected model has no vision support. every continuation re-sends the full history, the provider rejects it with a non-retryable capability error, and the same error renders endlessly in the tui ("This model does not support images." hundreds of times). nothing new gets persisted and the storm of retry renders garbles the transcript view into unreadable glyphs.
how image parts get there
ordinary use. most commonly tool results that embed screenshots — parts of shape {"type":"file","uri":"data:image/..."} inside content[].state.content[] of assistant messages. once one exists in history, every future send includes it.
why it never recovers
the rejection is deterministic, not transient — no retry can ever succeed — but the error path behaves like a retryable failure: the same message keeps being produced and rendered. on top of that, the repeated sends showed up in logs as Failed to drain Session: ... Rate limit exceeded spam (the same wedge family as #54538).
expected behavior, either one:
- strip or degrade image parts to text placeholders before sending when the active model declares no image support, with a one-time visible notice, or
- fail once with a clear actionable error ("this session contains N image parts, model X cannot accept images") and stop looping
repair path that worked (2.0.23)
opencode session export <id>— works, includes full content states- replace the
data:imagefile parts wholesale with text placeholders (blanking only the uri just turns into a "file not found" failure) - regenerate all message ids — see next defect
opencode session import— verified: same title, all messages, zero image uris
secondary defect: session import 500s on reused message ids with no useful error
importing an exported session fails with Failed to import session: Internal Server Error. the server logs an EffectDrizzleQueryError with the query and params but never surfaces the driver error to the client. cause: the export's message ids already exist in session_message (the original session still exists), so the insert hits a unique constraint. a fully synthetic session imports fine; any clone with reused message ids fails.
expected: re-key ids on import automatically, or at least report "message id already exists" instead of a bare 500.
secondary defect: unique (session_id, seq) 500s on the model endpoint
in the same window, unrelated live sessions on the same instance produced:
SQLiteError: UNIQUE constraint failed: session_message.session_id, session_message.seq
on POST /api/session/<id>/model (http 500). possibly the same write path — seq assignment may not be monotonic under concurrent writes. including it because it appeared alongside the above and looks related.
environment
- opencode 2.0.23, windows x64
- custom provider, non-multimodal model id
- related: thread payload hangs every request ~325s -> [504] Provider timed out, retry loop wedges the session, no circuit breaker #54538 (retry-loop wedge family)
Activity
opencode-agent commentedon Oct 14, 2026
Thanks for the detailed write-up and the repair steps! I think this is a duplicate of #52042.
In v2, image parts already in the session history are checked before every request (
unsupportedPartsinpackages/core/src/session/model-request.ts). That check replaces each image the model can't accept with a shortERROR: Cannot read …text note. It only does this when the model'scapabilities.inputleaves outimage. A custom-provider model with no declared capabilities defaults toinput: ["text", "image"]. So the stored screenshots are sent anyway, and the provider rejects every turn. The "This model does not support images." text comes from your provider.Workaround: declare the capabilities on your custom model, for example:
The check runs over the whole stored history on every request, so this should also fix sessions that are already stuck. You shouldn't need the export/edit/import repair. Switching the session to a model that accepts images also gets it working again.
Possible duplicates and related issues, ordered by likelihood:
UNIQUE constraint failed: session_message.session_id, session_message.seq500 (seq collisions); a related fix is proposed in fix(core): repair desynced session seq instead of dropping messages #54907.The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
FahadBinHussain commentedon Oct 14, 2026
thanks for the triage, this matches what we found. Closing as duplicate.
one addition worth checking: it's not only custom-provider models. the built-in
opencode/mimo-v2.6-flash-freeon the zen free tier also declares no capabilities, so it falls into the sameinput: ["text","image"]default and wedges identically when screenshots end up in tool results. we applied the capabilities override locally (provider.opencode.models."mimo-v2.6-flash-free"withinput: ["text"]) — if that override can't extend built-in providers, the built-in model definitions probably need the declaration upstream as part of the #52042 fix.also +1 on the import 500 (#54336): our workaround was regenerating every message id before import, which then succeeds. an explicit conflict error or auto re-key would have saved a lot of digging.
opencode-agent commentedon Oct 14, 2026
Thanks for confirming, and for the extra details!
MiMo on Zen: the local override is the right fix, and it does work for built-in providers. Entries under
provider.opencode.models.<id>in config have theircapabilitiesapplied on top of the built-in model (the merge inpackages/core/src/plugin/provider/opencode.ts, also in 2.0.23). Withinput: ["text"], image parts in the history, including tool-result screenshots, are swapped for a short text note before each request.One correction, though:
mimo-v2.6-flash-freedoesn't fall back to the default. The models.dev catalog that OpenCode uses declares its input as["text", "image", "audio", "video"], so OpenCode sends images on purpose. In #54538 you also found that a fresh session with this model and a pasted PNG worked. If the Zen free tier really does reject images for this model, the catalog entry is what needs fixing, and that's tracked on models.dev. Adding that case to #52042 would help too.Import 500: please add your +1 and the workaround (regenerating every message ID before import) on #54336, so they're tracked with that issue.
As said earlier, the bot will close this one as a duplicate of #52042.
opencode-agent commentedon Oct 15, 2026
Closing this as a duplicate of #52042, as discussed. Thanks again for the detailed report and the repair steps!
Where to follow each part:
session_message.sequnique-constraint 500s.If Zen keeps rejecting images for
mimo-v2.6-flash-freeeven though the catalog says it accepts them, please add that case to #52042 or report it on models.dev.