Skip to content

fix(session): sanitize image attachments before sending to API - #19555

Closed
kozak-codes wants to merge 2 commits into
anomalyco:devfrom
kozak-codes:fix/sanitize-image-attachments
Closed

kozak-codes wants to merge 2 commits into
anomalyco:devfrom
kozak-codes:fix/sanitize-image-attachments

Conversation

@kozak-codes

@kozak-codes kozak-codes commented Mar 28, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #4781

Type of change

  • Bug fix

What does this PR do?

When a tool (like read or the screenshot tool) returns an image attachment, it gets stored in session history and replayed to the API on every subsequent request. If that image violates provider limits, the session gets permanently stuck — every message fails with the same 400, even if you tell the model to stop using images.

Three cases cause this:

  • Unsupported MIME type (e.g. image/bmp, image/tiff) — providers only accept jpeg, png, gif, webp
  • Base64 payload over 5 MB — Anthropic's hard limit
  • PNG dimensions over 2000px on any side — Anthropic rejects these in multi-image requests

The fix adds these three guards to unsupportedParts() in transform.ts. Bad images are replaced with a descriptive error string in the context instead of being sent. Also normalizes image/jpg → image/jpeg since both are valid but only the latter passes the whitelist.

PNG dimensions are read from the IHDR header (first 32 bytes via atob) — no extra dependencies needed.

How did you verify your code works?

Hit both the 5 MB and 2000px errors in real sessions. Fixed them manually via DB surgery, then confirmed the guards here would have caught them before they were stored. Added 6 new unit tests covering all three failure modes plus the jpg normalization and valid-image passthrough cases. All 125 tests pass.

Screenshots / recordings

No UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Prevents sessions from getting stuck replaying image attachments that
exceed provider limits. Three new guards added to unsupportedParts():

- Unsupported MIME type: only image/jpeg, image/png, image/gif, image/webp
  are accepted (all major providers). image/jpg is normalized to image/jpeg.
  Anything else (bmp, tiff, svg, etc.) is replaced with a descriptive error.

- Size limit: base64 payload > 5 MB is rejected. Anthropic enforces a hard
  5 MB cap; exceeding it poisons the session history and causes every
  subsequent request to fail with a 400.

- Dimension limit: PNG images with any side > 2000px are rejected. Anthropic
  rejects these in multi-image requests with a 400. Dimensions are read from
  the PNG IHDR header without a full decode (fast, no deps).

Adds 6 new tests covering: unsupported MIME, jpg normalization, oversized
payload, oversized PNG dimensions, valid small PNG, all four accepted types.

Closes: anomalyco#4781
Related: anomalyco#9785, anomalyco#9512, BASIC-BIT#1
@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Mar 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@kozak-codes

Copy link
Copy Markdown
Author

Bump

@zeke

zeke commented Apr 10, 2026 •

Copy link
Copy Markdown
Contributor

I've been tracking the session-bricking bug across #4781, #14562, #21668, #12068, and #13865. This PR addresses the core issue cleanly.

The approach makes sense: validate images in unsupportedParts() before they're sent to the provider, and replace bad ones with error text. This covers the three failure modes (unsupported MIME, >5 MB base64, >2000px dimensions) without adding any dependencies.

This doesn't resize images (a user pasting a 6 MB screenshot will see an error instead of it just working), but that's a reasonable follow-up. The critical thing is stopping sessions from becoming permanently unrecoverable, which this does.

Multiple people on our team are hitting this bug regularly. Would appreciate a maintainer review. CI is all green.

@rekram1-node

Copy link
Copy Markdown
Collaborator

Automated PR Cleanup

Thank you for contributing to opencode.

Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions.

This PR was closed because it matched the following cleanup criteria:

  • The PR was created more than 1 month ago
  • The PR had fewer than 2 positive reactions
  • Positive reactions are counted as thumbs-up, heart, celebration, or rocket reactions on the PR

PRs created within the last month are not affected by this cleanup.

If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate.

Thanks again for taking the time to contribute.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Once I get an error I can't move on

3 participants