Skip to content

server: HTTP 500 on prompt with file attachment over ~3.2 MB (Base64 schema regex stack overflow) #58116

Closed as duplicate

Description

@JoseWangEs

Summary

Attaching a file larger than about 3.2 MB to a prompt makes POST /api/session/:id/prompt fail with HTTP 500. The failure happens while materializing the attachment: the Prompt.Base64 schema uses a backtracking-prone regex that overflows the call stack on large strings (RangeError: Maximum call stack size exceeded), which is surfaced as a schema InvalidValue instead of a clear size/format error. Attachments well under the documented 20 MiB limit are affected.

Environment

  • opencode version: 2.1.0 (server and TUI); desktop app 2.0.32 connects to the same local service
  • OS: macOS (Darwin 25.6.0, arm64)
  • Terminal: xterm-256color, COLORTERM=truecolor
  • Shell: /bin/zsh
  • Install/channel: npm global (@opencode/cli)
  • Active plugins: none found

Reproduction

  1. Take any file larger than ~3.2 MB (a 5.7 MB PDF in my case).
  2. Attach it to a prompt (paste the absolute path or drag it in), so the client sends a PromptInput.FileAttachment:
    { "uri": "file:///Users/me/Desktop/large.pdf", "name": "large.pdf" }
  3. Send the prompt.

Minimal reproduction of the underlying validator (same regex as Prompt.Base64, runs on the bundled Bun 1.4.2 and on Node):

const r = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;

r.test("A".repeat(4_400_000)); // true
r.test("A".repeat(4_500_000)); // RangeError: Maximum call stack size exceeded

Measured threshold on this machine: 4,473,912 base64 characters pass, 4,473,916 throw (about 3.2 MB of decoded data).

Expected Behavior

  • Accept the attachment (it is under the documented 20 MiB limit), or
  • Reject it with a 4xx and an explicit message (for example "attachment too large" or "unsupported attachment type"), never a 500.

Actual Behavior

POST /api/session/<id>/prompt returns HTTP 500 and the prompt is never sent to the model. Server log:

POST /api/session/<id>/prompt  http.status=500
cause="Error: Schema validation failed
    at SessionPrompt.normalizeImageAttachment
    ... Prompt.Base64 ... {"issue":{"_tag":"InvalidValue"}}"

Observed 7 times in a row, every attempt with the same 5.7 MB PDF.

Additional Context

  • SessionPrompt.normalizeImageAttachment returns { data: Prompt.Base64.make(base64) } for every non-image mime type, so a PDF (detected via the %PDF- magic bytes) always goes through this regex.

  • Base64 produced by Buffer.from(bytes).toString("base64") is always structurally valid, so the schema failure can only come from the regex itself failing on large input.

  • Per the V2 attachments docs, PDF and other unsupported binaries are not included in the model request anyway. Materializing them to a multi-megabyte base64 string only to fail the shape check is wasted work; rejecting unsupported binaries before materialization (with the documented "convert to text or PNG first" guidance) would be cheaper and clearer.

  • Suggested validator without the nested quantifier:

    const isBase64 = (s: string) =>
      s.length % 4 === 0 && s.length > 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(s);

    and/or catch RangeError and map it to a typed error instead of letting it become a schema InvalidValue.

  • Workaround I use now: pass the file path in the prompt and let the agent read it with a tool instead of attaching it. Reading the same 5.7 MB PDF through a tool works fine, so this is specific to the attachment path.

Activity

  1. opencode-agent commented on Oct 22, 2026

    @opencode-agent
    Contributor

    Thanks for the clear report and the minimal regex reproduction. I think this is a duplicate of #45558.

    It's the same failure: the Prompt.Base64 check in packages/schema/src/prompt.ts uses the repeated-group regex you quoted, and it fails on valid base64 once the string is a few MB long. As a result, any attachment over roughly 3–6 MB (depending on the runtime) returns HTTP 500 from POST /api/session/:id/prompt with Schema validation failed ... InvalidValue, even though it's under the 20 MiB limit. The regex is unchanged on the current dev branch. PR #51272 proposes a replacement without backtracking, but it hasn't been merged yet.

    Possible duplicates and related issues, ordered from most to least likely:

    Your suggestion to reject unsupported binaries like PDFs before encoding them is a good one. It would fit well as a comment on #45558 or #51272.

    Until the fix lands, your workaround of passing the file path and letting the agent read it with a tool avoids the problem. Converting the PDF to text first also works.

    The bot will close this issue as a duplicate of #45558 in 1 day unless you reply explaining how your problem is different. Subscribing to #45558 or #51272 will let you follow progress.

  2. opencode-agent commented on Oct 23, 2026

    @opencode-agent
    Contributor

    Closing this as a duplicate of #45558, since there hasn't been a reply saying how it's different. It's the same Prompt.Base64 regex failure, which gives HTTP 500 on POST /api/session/:id/prompt for attachments over a few MB. Your 5.7 MB PDF on 2.1.0 is one example. Closing just keeps the discussion in one place; the bug is still open. The proposed fix, PR #51272, hasn't been merged yet, so please subscribe to #45558 or #51272 to follow progress. Your idea of rejecting unsupported binaries before encoding them would be a good comment there too. Until then, your workaround still works: pass the path and let the agent read the file with a tool. Thanks again for the clear reproduction.

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