[PR #11952] fix: handle nested array items for Gemini schema validation #14000

Closed
opened 2026-02-16 18:18:49 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/11952

State: closed
Merged: Yes


Fixes #5832

Summary

Fixes Gemini API rejection of MCP tools with nested array schemas (2D arrays like z.array(z.array(z.any()))).


Problem

Gemini API rejects tools with nested array schemas where inner items are missing the type field.

Error

Error: * GenerateContentRequest.tools[0].function_declarations[50].parameters.properties[values].items.items: missing field.
* GenerateContentRequest.tools[0].function_declarations[51].parameters.properties[values].items.items: missing field.
* GenerateContentRequest.tools[0].function_declarations[55].parameters.properties[initialData].items.items: missing field.

Root Cause

  1. Nested array items were missing the type field - The existing fix only handled result.items == null, but didn't catch when items was an empty object {} without a type
  2. MCP tools were bypassing schema transformations entirely - MCP tools were not going through sanitizeGemini and other provider-specific schema transformations

Solution

1. Fixed nested array handling in sanitizeGemini

Extended the sanitization logic to assign default type "string" when items exists but has no type:

Before:

if (result.type === "array" && result.items == null) {
  result.items = {}
}

After:

if (result.type === "array") {
  if (result.items == null) {
    result.items = {}
  }
  if (typeof result.items === "object" && !Array.isArray(result.items) && !result.items.type) {
    result.items.type = "string"
  }
}

2. Extended MCP.tools() to apply schema transformations

MCP tools now accept a model parameter and go through the same schema transformation pipeline as built-in tools.


Files Changed

File Changes
packages/opencode/src/provider/transform.ts Extended sanitizeGemini to handle nested arrays with missing type
packages/opencode/src/mcp/index.ts Added model parameter to MCP.tools() for schema transformations
packages/opencode/src/session/prompt.ts Pass model to MCP.tools() call
packages/opencode/test/provider/transform.test.ts Added 5 test cases for nested array scenarios

Reproduction Steps

MCP causing the issue: google-docs-mcp

Command to trigger error:

opencode run "hi" --model google/gemini-3-flash

Problematic tools in the MCP:

Tool Parameter Schema
writeSpreadsheet values z.array(z.array(z.any()))
appendSpreadsheetRows values z.array(z.array(z.any()))
createSpreadsheet initialData z.array(z.array(z.any()))

JSON Schema sent to Gemini (before fix):

{
  "values": {
    "type": "array",
    "items": {
      "type": "array",
      "items": {}
    }
  }
}

The inner items: {} has no type, which Gemini rejects.


Testing

Automated Tests

  • All 98 transform tests pass
  • Full test suite: 852 tests pass, 0 fail
  • TypeScript typecheck passes

Manual Verification

  • Verified with google-docs-mcp tools on VPS with Gemini 3 Flash
  • All 55+ MCP tools now properly transform and are accepted by Gemini API
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/11952 **State:** closed **Merged:** Yes --- Fixes #5832 ## Summary Fixes Gemini API rejection of MCP tools with nested array schemas (2D arrays like `z.array(z.array(z.any()))`). --- ## Problem Gemini API rejects tools with nested array schemas where inner items are missing the `type` field. ### Error ``` Error: * GenerateContentRequest.tools[0].function_declarations[50].parameters.properties[values].items.items: missing field. * GenerateContentRequest.tools[0].function_declarations[51].parameters.properties[values].items.items: missing field. * GenerateContentRequest.tools[0].function_declarations[55].parameters.properties[initialData].items.items: missing field. ``` ### Root Cause 1. **Nested array items were missing the `type` field** - The existing fix only handled `result.items == null`, but didn't catch when `items` was an empty object `{}` without a type 2. **MCP tools were bypassing schema transformations entirely** - MCP tools were not going through `sanitizeGemini` and other provider-specific schema transformations --- ## Solution ### 1. Fixed nested array handling in `sanitizeGemini` Extended the sanitization logic to assign default type `"string"` when `items` exists but has no type: **Before:** ```typescript if (result.type === "array" && result.items == null) { result.items = {} } ``` **After:** ```typescript if (result.type === "array") { if (result.items == null) { result.items = {} } if (typeof result.items === "object" && !Array.isArray(result.items) && !result.items.type) { result.items.type = "string" } } ``` ### 2. Extended MCP.tools() to apply schema transformations MCP tools now accept a model parameter and go through the same schema transformation pipeline as built-in tools. --- ## Files Changed | File | Changes | |------|---------| | `packages/opencode/src/provider/transform.ts` | Extended `sanitizeGemini` to handle nested arrays with missing type | | `packages/opencode/src/mcp/index.ts` | Added model parameter to `MCP.tools()` for schema transformations | | `packages/opencode/src/session/prompt.ts` | Pass model to MCP.tools() call | | `packages/opencode/test/provider/transform.test.ts` | Added 5 test cases for nested array scenarios | --- ## Reproduction Steps **MCP causing the issue:** [google-docs-mcp](https://github.com/a-bonus/google-docs-mcp) **Command to trigger error:** ```bash opencode run "hi" --model google/gemini-3-flash ``` **Problematic tools in the MCP:** | Tool | Parameter | Schema | |------|-----------|--------| | `writeSpreadsheet` | `values` | `z.array(z.array(z.any()))` | | `appendSpreadsheetRows` | `values` | `z.array(z.array(z.any()))` | | `createSpreadsheet` | `initialData` | `z.array(z.array(z.any()))` | **JSON Schema sent to Gemini (before fix):** ```json { "values": { "type": "array", "items": { "type": "array", "items": {} } } } ``` The inner `items: {}` has no type, which Gemini rejects. --- ## Testing ### Automated Tests - All 98 transform tests pass - Full test suite: 852 tests pass, 0 fail - TypeScript typecheck passes ### Manual Verification - Verified with google-docs-mcp tools on VPS with Gemini 3 Flash - All 55+ MCP tools now properly transform and are accepted by Gemini API
yindo added the pull-request label 2026-02-16 18:18:49 -05:00
yindo closed this issue 2026-02-16 18:18:49 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#14000