anomalyco / anomalyco/opencode
[bug] Gemini rejects MCP tool with nullable array schema (type: "array","null"): languages.items predicate failed + any_of0.items` missing field
Open
@nexxeln is already working on this.
Since Sep 9, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- Avg merge
- 7h 2m
- Merged PRs (30d)
- 384
Description
Description
Description
Any request to a Gemini model fails with 400 INVALID_ARGUMENT when the @sylphx/pdf-reader-mcp MCP server is enabled — even a plain hello with no PDF involved. Gemini validates all function declarations up front, so one incompatible tool schema breaks every request. The same setup works fine on DeepSeek / OpenAI-compatible providers.
Error
- GenerateContentRequest.tools[0].function_declarations[9].parameters.properties[languages].items: field predicate failed: $type == Type.ARRAY
- GenerateContentRequest.tools[0].function_declarations[9].parameters.properties[languages].any_of[0].items: missing field.
Root cause
The MCP server's raw tools/list schema (queried directly, v4.1.3 = latest) declares:
"languages": { "items": { "type": "string" }, "type": ["array", "null"] }
This is valid JSON Schema, but after opencode/AI-SDK converts it to Gemini's function-calling schema, the multi-type array is split into anyOf, producing two invalid halves:
- top-level items left behind while type is no longer ARRAY → predicate failed: $type == Type.ARRAY
- a bare { "type": "array" } branch inside anyOf with no items → any_of[0].items: missing field (Gemini requires items on every array)
The tool has ~15 similar union-typed fields (["string","null"], ["integer","null"], plus a nested sources.regions: ["array","null"]), so patching a single field is not enough — the converter/sanitizer needs to handle the pattern.
Repro - mcp.pdf-reader: npx @sylphx/pdf-reader-mcp (v4.1.3), enabled: true
- opencode run "hello" -m google/gemini-3.8-flash (also repros on gemini-2.5-flash-lite, gemini-3.5-flash-lite) → 400 above
- Set the server enabled: false, or a per-agent "pdf-reader_*": "deny" → hello-ok ✅ (verified A/B; deny proves the tools are excluded from declarations and the request then passes)
Expected / proposed fix
Extend sanitizeGemini in transform.ts (cf. #11889) to normalize multi-entry type arrays on the Gemini path, e.g. collapse type: ["array","null"] → type: "array", nullable: true keeping items on the array branch (same class of fix as LibreChat #13623 sanitizeGeminiSchema, and related to #3140 / #14509). Gemini-side nullable is the documented way to express optionality — no anyOf needed.
Environment
- opencode 1.18.29
- @sylphx/pdf-reader-mcp@4.1.3 (npm latest, verified via tools/list over stdio)
- models: google/gemini-3.8-flash (primary target), google/gemini-3.5-flash-lite
Related - #11889 (sanitize non-object properties/required)
- #14509 (anyOf sibling fields break all Gemini requests)
- sst/opencode#3140
Plugins
pdf-reader
OpenCode version
v1.18.27
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
Ubuntu 22.04
Terminal
Ptyxis
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.