Skip to content

[BUG] Sessions still brick when exceeding provider image-count limits in OpenCode 2.0 #55060

Closed as duplicate

Description

@Sugamsss

Problem

Following up on #47487 (closed during the 2.0 transition): this still reproduces on OpenCode 2.0.

In OpenCode 2.0, boundImages() in packages/core/src/session/model-request.ts bounds total image bytes when exceeding 25 MiB. However, it enforces no check on image count.

If an agent takes 51 screenshots that total under 25 MiB (for example, 51 small browser verification crops totaling ~3 MiB), OpenCode sends all 51 images to the provider. Providers with a 50-image ceiling (like OpenAI, Azure, and Console Go) reject the request with HTTP 400:
request contains 51 images, exceeding the maximum of 50 allowed per request

In packages/ai/src/provider-error.ts, this rejection is not classified as context overflow. It fails as a generic InvalidRequestError, so automatic compaction and recovery never trigger. Every subsequent user prompt fails identically, leaving the session permanently dead.

Furthermore, when core's boundImages() does remove an image, it replaces it with a generic blind stub:
[This image was removed to reduce the request size and is no longer visible. Do not make claims about its contents from memory. If needed, retrieve it again with an available tool or ask the user to attach it again.]
Because this stub contains no file path, tool name, or task context, the model has no way to know which file to re-read if the user asks about it later.

Proposed Core Fix

  1. Count bounding in model-request.ts: Add an image count ceiling to boundImages() alongside the byte trigger, so requests with many small images don't breach provider limits.
  2. Actionable recall instead of a blind stub: When an image is replaced, preserve the source file path (or tool name) in the placeholder text. That way, the model actually knows what was removed and can use read to pull that specific image back into context if the user asks about it.
  3. Error classification in provider-error.ts: Add image-count rejection patterns to patterns so provider count errors trigger context overflow recovery instead of an unrecoverable crash.

We have a working implementation and battle-tested this pattern with zero dependencies in opencode-prune-images (PR #55058). Happy to contribute a targeted PR for core if the team would like one.

Activity

  1. opencode-agent commented on Oct 13, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed follow-up and for pointing to the exact code. I checked current dev, and you're right: boundImages() only checks total image bytes, never the image count, and provider-error.ts doesn't recognise image-count rejections, so overflow recovery never starts.

    I think this is a duplicate of #47721, which is still open and reports the same problem on v2: a session collects more than 50 images, the provider returns a 400, and every later request fails.

    Related issues, ordered from most to least likely to be the same problem:

    Your proposals (an image-count cap in boundImages(), a stub that names the file it replaced, and classifying the error) would be useful on #47721, and maintainers can say there whether they want a PR.

    The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.

  2. opencode-agent commented on Oct 14, 2026

    @opencode-agent
    Contributor

    Closing this as a duplicate of #47721. That issue reports the same v2 problem: once a session holds more images than the provider allows per request, the 400 isn't treated as context overflow and the session can't recover. We waited a day for a reply in case your problem was different, and none came.

    Please follow #47721 for updates. Your three proposals (an image-count cap in boundImages(), a removal stub that keeps the file path, and classifying image-count errors) would be useful there, and maintainers can say on that issue whether they'd like a PR. #48781 covers the same root cause with PDF and PNG reads. If your case turns out to be different, reply here and we can reopen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions