Repository navigation
Description
Summary
OpenAI Responses session continuation can fail locally with OpenAI Responses media must contain valid base64 after reading a PDF. The PDF data is valid canonical base64, but validateMedia rejects it before the request reaches OpenAI.
Environment
- opencode version:
opencode2 v0.0.0-dev-202608161625 - OS:
Linux p1 7.0.0-29-generic #29-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 17 20:52:35 UTC 2026 x86_64 GNU/Linux - Terminal:
TERM=xterm-256color,COLORTERM=truecolor,TERM_PROGRAMunset - Shell:
/usr/bin/fish - Install/channel: local/dev build
- Active plugins: none for reproduction; started with
OPENCODE_CONFIG_CONTENT='{"$schema":"https://opencode.ai/config.json","plugin":[]}'
Reproduction
-
Start opencode in a workspace with plugins disabled:
OPENCODE_CONFIG_CONTENT='{"$schema":"https://opencode.ai/config.json","plugin":[]}' \ OPENCODE_CONFIG_PROJECT_DISABLE=1 \ opencode --standalone -
Use native OpenAI Responses, e.g.
openai/gpt-5.5. -
Ask the agent to read a local PDF from disk with the
readtool. -
Continue the session after the PDF read-tool result is produced.
Expected Behavior
The valid PDF data URL from the read-tool result should be accepted by local media validation and lowered as OpenAI Responses input_file content, or otherwise handled with a clear size/capability error if unsupported.
Actual Behavior
The session continuation fails locally with:
OpenAI Responses media must contain valid base64
The failure happens before provider submission in:
packages/ai/src/protocols/shared.ts
Specifically, validateMedia rejects the PDF Content.file.uri when it is replayed through:
packages/ai/src/protocols/open-responses.ts
lowerToolResultContentItem -> lowerMedia -> ProviderShared.validateMedia
Additional Context
The failing media candidate is the PDF returned by the read tool:
- MIME:
application/pdf - URI prefix:
data:application/pdf;base64,JV... - data URL length:
8125872 - base64 payload length:
8125844 - decoded bytes:
6094383 base64.length % 4 === 0- no invalid base64 characters
- no internal padding
Buffer.from(base64, "base64").toString("base64") === base64
However, this regex in packages/ai/src/protocols/shared.ts returns false for the valid large payload:
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/A simpler character/padding regex passes, and the existing canonical Buffer round-trip check also proves the data is valid.
Relevant history:
- fix(core): make V2 reads media-aware and binary-safe #31038 introduced strict
validateMediaand the grouped base64 regex. - feat(ai): support PDF inputs #38253 added PDF lowering for OpenAI Responses.
- refactor(ai): make OpenAI Responses extend Open Responses #38681 moved the current lowering into
open-responses.ts.
A minimal fix may be to replace the grouped regex with a simpler base64 character/padding check and keep the existing length and canonical re-encode checks as the authoritative validation.
Activity
altendky commentedon Aug 16, 2026
i would be happy to provide a pr, but i understand it might be easier for you to do so yourself.
opencode-agent commentedon Aug 16, 2026
Fixed in #42921.
The AI protocol layer no longer applies the shared grouped base64 regex, canonical re-encode check, or generic media size ceilings before provider submission. Media lowering now only normalizes bytes, raw base64, and data URLs into the wire shape required by each protocol, while retaining route-local MIME checks where a protocol cannot represent the input.
For OpenAI Responses specifically, PDF tool-result content is preserved as a data URL and lowered directly to
input_file. A regression test covers replaying a PDF with an approximately 8.1 MB base64 payload, matching the reported failure size.altendky commentedon Aug 16, 2026
thanks!