Mentioning/Opening large xlsx file crashes session · Issue #50336 · anomalyco/opencode · GitHub
Skip to content

Mentioning/Opening large xlsx file crashes session #50336

Open

Description

@madflow

Description

  • Mentioning a larger xlsx file 12MB with @foo.xlsx crashes the session.
  • Workaround - use sth. like "foo.xlsx" how big?
timestamp=2026-09-21T09:56:44.764Z level=INFO run=1638ac46 message=event event.id=evt_0c365825c001i9glaoT4GrZf6D event.created=1789984604764 event.type=provider.updated event.location.directory=/private/var/folders/9l/l_jnc13s4rj9nr7ylz0_ypdr0000gn/T/opencode event.location.workspaceID=undefined event.data={}
timestamp=2026-09-21T09:56:44.779Z level=INFO run=1638ac46 message=event event.id=evt_0c365826b001TJDtRbm0U152Yg event.created=1789984604779 event.type=model.updated event.location.directory=/private/var/folders/9l/l_jnc13s4rj9nr7ylz0_ypdr0000gn/T/opencode event.location.workspaceID=undefined event.data={} http.span=300065 role=server
timestamp=2026-09-21T09:56:45.352Z level=INFO run=fb99b67b message="cli starting" version=2.0.11 channel=latest local=false args=[] role=cli
timestamp=2026-09-21T09:56:45.392Z level=INFO run=fb99b67b message="event stream connecting" component=client attempt=0 role=cli
timestamp=2026-09-21T09:56:45.395Z level=INFO run=fb99b67b message="event stream connected" component=client role=cli
timestamp=2026-09-21T09:56:45.400Z level=INFO run=fb99b67b message="plugin reconciliation started" component=plugin id=1 role=cli
timestamp=2026-09-21T09:56:45.406Z level=INFO run=fb99b67b message="plugin reconciliation completed" component=plugin id=1 durationMs=6 plugins=12 role=cli
timestamp=2026-09-21T09:56:45.425Z level=INFO run=fb99b67b message="plugin reconciliation started" component=plugin id=2 role=cli
timestamp=2026-09-21T09:56:45.432Z level=INFO run=fb99b67b message="plugin reconciliation completed" component=plugin id=2 durationMs=7 plugins=12 role=cli
timestamp=2026-09-21T09:56:45.432Z level=INFO run=fb99b67b message="plugin reconciliation started" component=plugin id=3 role=cli
timestamp=2026-09-21T09:56:45.432Z level=INFO run=fb99b67b message="plugin reconciliation completed" component=plugin id=3 durationMs=0 plugins=12 role=cli
timestamp=2026-09-21T09:56:45.447Z level=INFO run=fb99b67b message="plugin reconciliation started" component=plugin id=4 role=cli
timestamp=2026-09-21T09:56:45.452Z level=INFO run=fb99b67b message="plugin reconciliation completed" component=plugin id=4 durationMs=5 plugins=12 role=cli
timestamp=2026-09-21T09:56:45.862Z level=INFO run=fb99b67b message="update check" current=2.0.11 latest=2.0.12 role=cli
timestamp=2026-09-21T09:56:45.863Z level=INFO run=fb99b67b message="OpenCode update available" current=2.0.11 latest=2.0.12 action=notify role=cli
timestamp=2026-09-21T09:56:46.412Z level=INFO run=1638ac46 message="spawning process" command=/opt/homebrew/bin/rg args="[\"--no-config\",\"--files\",\"--glob=!**/.git/**\",\".\"]" cwd=/private/tmp/br0ken http.span=4 role=server
timestamp=2026-09-21T09:56:48.335Z level=INFO run=1638ac46 cause="Error: Schema validation failed\n    at <anonymous> (/$bunfs/root/chunk-5tvdqet6.js:4:36213)\n    at <anonymous> (/$bunfs/root/chunk-f79f68bn.js:122:299)\n    at SessionPrompt.normalizeImageAttachment (/$bunfs/root/chunk-f79f68bn.js:122:23)\n    at SessionPrompt.normalizeImageAttachment (definition) (/$bunfs/root/chunk-f79f68bn.js:122:193)\n    at SessionPrompt.materializeAttachment (/$bunfs/root/chunk-fzekn76j.js:24:19733)\n    at SessionPrompt.materializeAttachment (definition) (/$bunfs/root/chunk-f79f68bn.js:120:1878)\n    at SessionPrompt.prepare (/$bunfs/root/chunk-f79f68bn.js:137:4860)\n    at SessionPrompt.prepare (definition) (/$bunfs/root/chunk-f79f68bn.js:120:834)\n    at Session.prompt (/$bunfs/root/chunk-pa155s7f.js:432:7403)\n    at Session.prompt (definition) (/$bunfs/root/chunk-f79f68bn.js:137:4621)\n    at Effect.fn (/$bunfs/root/chunk-pa155s7f.js:56:6933)\n    at Effect.fn (definition) (/$bunfs/root/chunk-pa155s7f.js:432:7363) {\n  [cause]: Error: {\"~effect/SchemaIssue/Issue\":\"~effect/SchemaIssue/Issue\",\"_tag\":\"Composite\",\"ast\":{\"~effect/Schema\":\"~effect/Schema\",\"checks\":[{\"_tag\":\"Filter\",\"annotations\":{\"expected\":\"a string matching the RegExp ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$\",\"representation\":{\"id\":\"effect/schema/isPattern\",\"payload\":{\"source\":\"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$\",\"flags\":\"\"}},\"arbitrary\":{\"constraint\":{\"patterns\":[\"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$\"]}},\"identifier\":\"Prompt.Base64\"},\"aborted\":false}],\"_tag\":\"String\"},\"issues\":[{\"~effect/SchemaIssue/Issue\":\"~effect/SchemaIssue/Issue\",\"_tag\":\"Filter\",\"filter\":{\"_tag\":\"Filter\",\"annotations\":{\"expected\":\"a string matching the RegExp ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$\",\"representation\":{\"id\":\"effect/schema/isPattern\",\"payload\":{\"source\":\"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$\",\"flags\":\"\"}},\"arbitrary\":{\"constraint\":{\"patterns\":[\"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$\"]}},\"identifier\":\"Prompt.Base64\"},\"aborted\":false},\"issue\":{\"~effect/SchemaIssue/Issue\":\"~effect/SchemaIssue/Issue\",\"_tag\":\"InvalidValue\"}}]}\n}" http.span=66 role=server http.method=POST http.url=/api/session/ses_f3c9a701dffe1oxiskq13lE21O/prompt http.status=500
timestamp=2026-09-21T09:57:04.132Z level=INFO run=1638ac46 message=event event.id=evt_0c365ce03001T6kgO6az9e0kkC event.created=1789984624132 event.type=provider.updated event.location.directory=/private/tmp/foo event.location.workspaceID=undefined event.data={}
timestamp=2026-09-21T09:57:04.144Z level=INFO run=1638ac46 message=event event.id=evt_0c365ce10001vKJXLp3nHZb2BM event.created=1789984624144 event.type=model.updated event.location.directory=/private/tmp/foo event.location.workspaceID=undefined event.data={} http.span=1199984 role=server

Plugins

No response

OpenCode version

v2.0.12

Steps to reproduce

  1. @foo.xlsx large xlsx file

foo.xlsx

Screenshot and/or share link

Image

Operating System

macOS latest

Terminal

Ghostty

Activity

  1. darellchua2 commented on Sep 25, 2026

    @darellchua2

    Same root cause as #45558: the Prompt.Base64 pattern check in packages/schema/src/prompt.ts uses a (?:X{4})* regex that fails on multi-MB strings (silently returns false under Bun/JSC, the runtime the shipped binary embeds; throws RangeError under V8). materializeAttachment runs it on the base64 of any @-mentioned file up to 20 MB, which is why a 12 MB xlsx crashes the prompt while small files work. Analysis, repro, and a parity-safe replacement in #45558 — a PR referencing both issues is on the way.

  2. atsyplenkov commented on Oct 7, 2026

    @atsyplenkov

    Thanks for the report — I hit the same crash and while narrowing it down I think I found the missing piece. It does not seem to be specific to xlsx, and it is not really about the attachment size either: the Prompt.Base64 schema pattern itself silently fails on long strings.

    I can reproduce it without OpenCode at all, just Bun 1.4.0 and a regex test on base64 that Buffer produced (so the input is valid base64 by construction — it round-trips through Buffer.from(b64, "base64") without loss):

    const re = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/
    const b64 = Buffer.alloc(n, 0x41).toString("base64")
    re.test(b64)
    n b64.length re.test(b64)
    6 000 000 8 000 000 true
    6 150 000 8 200 000 true
    6 200 000 8 266 668 false
    6 250 000 8 333 336 false

    Bisecting the length (in steps of 4) gives 8 257 528 as the longest passing string and 8 257 532 as the shortest failing one — suspiciously close to 2^23 − 2^17 = 8 257 536. The string stays valid base64 throughout; the regex just gives up. On Node 26 (V8) the same call throws RangeError: Maximum call stack size exceeded, so the pattern looks pathological on both engines — JSC fails silently, which then surfaces as the schema InvalidValue from the logs above.

    This matches the OpenCode behavior exactly. Minimal repro through the API, no plugins, no first-message requirement — any message carrying the attachment does it:

    opencode api post /api/session --data '{"title":"repro","location":{"directory":"/tmp/repro"}}'
    opencode api post /api/session/ses_XXX/prompt \
      --data '{"text":"hi","files":[{"uri":"file:///tmp/repro/big.docx","name":"big.docx"}]}'
    

    A 6 150 000-byte file goes through, a 6 200 000-byte file returns HTTP 500 every time, so the effective limit is ~6.19 MB of raw bytes per binary attachment (I tried .docx and .png; text/plain files go through the Read path and are unaffected). For what it is worth, when the big attachment happens to be in the first message the TUI reports this as "Failed to set up session — UnexpectedStatus: 500", which sent me looking in completely the wrong direction at first.

    I suspect the same validation is also what breaks #45558 and #51350, although those look like genuinely non-base64 input (a data: prefix and such) rather than the length limit here.

    If the diagnosis looks right, a fix could be to validate with something linear instead of the quantified-group pattern, e.g. /^[A-Za-z0-9+/]*={0,2}$/ together with a separate length % 4 === 0 check — I believe the two are equivalent for the standard alphabet, and neither engine has to backtrack. A size cap would only move the cliff, since the pattern is what chokes.

    Happy to prepare a PR if that helps.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions