Skip to content

ai: OpenAI Responses rejects valid large PDF base64 during tool-result replay #42914

Closed

Description

@altendky

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_PROGRAM unset
  • 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

  1. 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
  2. Use native OpenAI Responses, e.g. openai/gpt-5.5.

  3. Ask the agent to read a local PDF from disk with the read tool.

  4. 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:

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

  1. altendky commented on Aug 16, 2026

    @altendky
    ContributorAuthor

    i would be happy to provide a pr, but i understand it might be easier for you to do so yourself.

  2. opencode-agent commented on Aug 16, 2026

    @opencode-agent
    Contributor

    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.

  3. altendky commented on Aug 16, 2026

    @altendky
    ContributorAuthor

    thanks!

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions