Skip to content

Gemini requests fail with 400 exclusiveMinimum — numeric constraints only stripped for gpt-oss models #37

Closed

Description

@CultureDigitali

Summary

Gemini requests routed through the Antigravity endpoint fail with HTTP 400 when the request includes tools, because OpenCode's built-in tool schemas contain JSON-Schema numeric constraints (e.g. exclusiveMinimum: 0 on glob/grep limit fields) and the plugin forwards them unchanged. Google's Cloud Code endpoint strictly validates the protobuf payload and rejects unknown fields.

Repro

opencode run --model google/antigravity-gemini-3.8-flash "Reply with exactly this word and nothing else: OK"

Response (Status 400):

Invalid JSON payload received. Unknown name "exclusiveMinimum" at 'request.tools[0].function_declarations[1].parameters.properties[3].value': Cannot find field.
Invalid JSON payload received. Unknown name "exclusiveMinimum" at 'request.tools[0].function_declarations[2].parameters.properties[5].value': Cannot find field.
Invalid JSON payload received. Unknown name "exclusiveMinimum" at 'request.tools[0].function_declarations[8].parameters.properties[2].value': Cannot find field.

Debug info: Requested Model antigravity-gemini-3.8-flash, Effective Model gemini-3.8-flash-medium, Project aicode-consumers, Endpoint https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse. Same failure on antigravity-gemini-3.1-pro.

Environment

  • Plugin @cortexkit/opencode-antigravity-auth 3.0.2 (npm)
  • OpenCode 2.0.28 (GA server path, background service)
  • Node v20.20.2, macOS arm64

Root cause (v3.0.2 bundle)

In dist/server.js, applyGeminiTransforms calls:

const result = normalizeGeminiTools(payload, {
  moveNumericConstraintsToDescription: model.toLowerCase().startsWith("gpt-oss-")
});

And in toGeminiSchema, numeric constraints (exclusiveMinimum, minimum, maximum, minLength, …) are only moved to the description hint when options.moveNumericConstraintsToDescription is truthy — otherwise they fall through to result[key] = value and are sent verbatim. So every non-gpt-oss Gemini request carrying tools with numeric constraints gets a 400 from Google.

Expected

Strip (or move to description) numeric schema constraints for Gemini models too, not just gpt-oss-* — the machinery in toGeminiSchema already supports it via the flag.

Workaround verified

Disabling tools for the model ("tools": {"*": false} on a test agent) makes the same request succeed and return a correct response, confirming auth/quota/model routing are all fine and this is purely a schema-sanitization gap.

Activity

  1. CultureDigitali commented on Oct 13, 2026

    @CultureDigitali
    Author

    Additional findings from real-world testing (same setup as above):

    1. A second, broader error class from MCP tool schemas. With MCP servers attached (TUI session), Gemini requests fail with a different 400 family:

    GenerateContentRequest.tools[0].function_declarations[1].parameters.properties[fields].items: field predicate failed: $type == Type.ARRAY
    GenerateContentRequest.tools[0].function_declarations[1].parameters.properties[fields].any_of[0].items: missing field.
    GenerateContentRequest.tools[0].function_declarations[16].parameters.properties[size].properties: only allowed for OBJECT type
    GenerateContentRequest.tools[0].function_declarations[18].parameters.properties[pages].items: field predicate failed: $type == Type.ARRAY
    GenerateContentRequest.tools[0].function_declarations[18].parameters.properties[pages].any_of[0].items: missing field.
    GenerateContentRequest.tools[0].function_declarations[20].parameters.properties[files].items: field predicate failed: $type == Type.ARRAY
    GenerateContentRequest.tools[0].function_declarations[20].parameters.properties[files].any_of[0].items: missing field.
    

    So it's not just numeric constraints: anyOf wrappers, stray items on non-ARRAY types, and properties on non-OBJECT types all pass through unsanitized on this path. A full strict-mode schema normalizer (strip/convert anyOf/oneOf, drop items unless type: ARRAY, drop properties unless type: OBJECT, handle numeric constraints) is needed for the Gemini-via-Antigravity path, like the official AI SDK google provider does.

    2. provider.<id>.models.<mid>.tools is silently dropped by OpenCode v2 config parsing. Setting per-model tool disables (e.g. provider.google.models.antigravity-gemini-3.8-flash.tools = {glob: false, ...}) has no effect — opencode debug config shows the model entry arriving as {}. Users currently cannot work around this per model.

    3. Verified workaround: agent-level explicit tool disables DO work. An agent with "tools": {"glob": false, "grep": false, "webfetch": false} makes antigravity-gemini-3.8-flash respond correctly (remaining core tools accepted). Note: "tools": {} does NOT disable anything (empty = all enabled), and project-level agents require a service restart to register.

  2. agauth-alfonso commented on Oct 23, 2026

    @agauth-alfonso

    Thanks for the detailed report and the follow-up examples. The exclusiveMinimum/exclusiveMaximum problem you hit on 3.0.2 was fixed in 3.0.3 and is included in the current 3.0.10. Integer exclusive bounds are now converted to the supported inclusive bounds, and other exclusive bounds become hints in the parameter description, so Gemini no longer receives those fields. Please upgrade to 3.0.10, and restart the OpenCode background service so it loads the new plugin.

    Your MCP examples point to a separate problem, which we've confirmed: a schema node that isn't an array can still carry items, and a node that isn't an object can still carry properties. We're fixing those checks without removing supported union schemas. If an MCP tool still fails after you upgrade, could you share one minimal failing tool declaration? Remove private names and descriptions, but keep the schema structure. We don't need credentials or full request logs.

  3. agauth-alfonso commented on Oct 23, 2026

    @agauth-alfonso

    Fixed in 3.0.11. Gemini tool schemas no longer keep items on a part that isn't an array, or properties on a part that isn't an object. Supported union schemas are unchanged. Please upgrade and restart OpenCode. If an MCP tool still fails after that, please open a new issue with a minimal sanitized schema.

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