anomalyco / anomalyco/opencode

[Bug]: unsupported or oversized image attachment aborts the entire prompt (HTTP 400) in the user-message path

Open
#43,262 1 comment 1 reaction 1 assignee View on GitHub

@neriousy is already working on this.

Since Aug 18, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

Attaching an image in a format the Photon-based resizer cannot decode (e.g. AVIF, HEIC, BMP, TIFF) — or an image too large to be resized below the inline limit — makes the entire prompt request fail with a 400 instead of degrading gracefully.

Expected Behavior

A single undecodable/oversized image attachment should not abort the whole message. It should be dropped (or replaced with a text note) while the rest of the prompt still sends — exactly like the tool-result path does today.

Current Behavior

packages/opencode/src/session/prompt.ts (user-message path, createUserMessage) runs image.normalize(part) inside a plain Effect.forEach that only catches Image.ResizerUnavailableError:

const parts = yield* Effect.forEach(resolvedParts, (part) =>
  part.type === "file" && part.mime.startsWith("image/")
    ? image.normalize(part).pipe(
        Effect.catchIf(
          (error) => error instanceof Image.ResizerUnavailableError,
          () => Effect.succeed(part),
        ),
      )
    : Effect.succeed(part),
)

Effect.forEach fails fast. If image.normalize throws Image.DecodeError (unsupported format) or Image.SizeError (cannot be resized below max_base64_bytes), the whole createUserMessage effect fails → promptSvc.prompt fails → the HTTP handler (httpapi/handlers/session.ts) maps it to a 400 Bad Request. The image message can never be sent.

Verified with the real @silvia-odwyer/photon-node@0.3.4 dependency: PhotonImage.new_from_byteslice throws for AVIF, HEIC, and BMP byte inputs, while PNG/JPEG/WebP decode fine.

The tool-result path (processor.ts) already handles this correctly with Effect.exit + filtering + an [N image omitted...] note. The user-message path is the asymmetric one.

Steps to Reproduce

  1. In the TUI, paste a local .avif (or .heic / .bmp) image path — the TUI attachment picker explicitly accepts .avif (packages/tui/src/component/prompt/local-attachment.ts).
  2. Send the prompt with the attached image.
  3. The request fails with HTTP 400; the message is never sent.

Impact

Any user with a modern camera/phone screenshot (HEIC) or an AVIF screenshot, or any image that cannot be compressed under the 5MB inline limit, hits a hard failure with no way to send the message at all.

Suggested Fix

Mirror the processor.ts pattern: catch normalize failures per-part (Effect.exit / Effect.catchAll), drop or replace the failing image with a synthetic text note, and keep the prompt alive.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.