Skip to content

fix(gemini): strip tilde-prefixed Standard Schema keys from tool parameters - #14279

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
hartmark:fix/gemini-tilde-optional-schema-key
Sep 22, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
hartmark:fix/gemini-tilde-optional-schema-key

Conversation

@hartmark

Copy link
Copy Markdown
Contributor

Problem

Gemini/antigravity returns a hard 400 the moment a tool's parameter schema contains a ~optional key:

[400]: Invalid JSON payload received. Unknown name "~optional" at 'tools[0].function_declarations[26].parameters.properties[1].value': Cannot find field.

This isn't a one-off — it 400s the entire request, so every Gemini-family model in a combo's fallback chain fails identically. Confirmed live in production: this exact error took down 100% of a combo's usable fallbacks for ~18 hours. The two candidates ahead of the Gemini models in that combo (oc/big-pickle, oc/mimo-v2.5-free) were OpenCode free-tier models, permanently inaccessible via API regardless of auth state — so once the Gemini fallbacks also failed, the whole combo failed closed with no working target at all.

Root cause

~-prefixed keys are the Standard Schema convention (adopted by Zod 4+, Valibot, ArkType) for internal/vendor metadata — namespaced with a leading ~ specifically so it can never collide with a real schema property name. A tool built from one of those libraries leaked a literal ~optional key into a property's subschema.

GEMINI_UNSUPPORTED_SCHEMA_KEYS already lists the plain "optional" string (for a different, older non-standard convention), but removeUnsupportedKeywords's exact-match check (keywords.has(key)) doesn't match the tilde-prefixed form, so it survived sanitization and reached Gemini's OpenAPI 3.0 schema subset, which rejects the whole request on the unrecognized field.

Fix

Strip any ~-prefixed key at every schema level, the same way x- vendor extensions are already stripped in the same loop:

if (keywords.has(key) || key.startsWith("x-") || key.startsWith("~")) {
  delete record[key];
}

This covers ~optional and any other Standard Schema metadata key the same libraries may emit (e.g. ~standard), rather than only patching this one literal key.

Testing

  • New regression test (tests/unit/gemini-standard-schema-tilde-optional.test.ts): confirmed failing on unpatched code with the exact assertion message, confirmed passing after the fix.
  • Full existing Gemini/schema-stripping suite (495 tests across tests/unit/gemini-*.test.ts and friends) still green — no regressions.
  • Verified live: after hot-reloading this fix into a running instance, a real end-to-end chat request that had been failing with the exact ~optional 400 for ~18 hours succeeded immediately.

…meters

Gemini/antigravity returned a hard 400 ("Unknown name \"~optional\" ...
Cannot find field") the moment a tool's parameter schema contained a
`~optional` key, taking down every Gemini-family model in a combo's
fallback chain at once -- confirmed live: this exact error killed 100% of
a production combo's usable fallbacks for ~18 hours (the two remaining
candidates ahead of it were OpenCode free-tier models, permanently
inaccessible via API regardless).

Root cause: `~`-prefixed keys are the Standard Schema convention (Zod 4+,
Valibot, ArkType) for internal/vendor metadata, namespaced with a leading
`~` specifically so it can never collide with a real schema property name.
A tool built from one of those libraries leaked a literal `~optional` key
into a property's subschema. GEMINI_UNSUPPORTED_SCHEMA_KEYS already listed
the plain `"optional"` string, but `removeUnsupportedKeywords`'s exact-match
check doesn't catch the tilde-prefixed form, so it survived sanitization
and Gemini's OpenAPI 3.0 schema subset rejected the whole request.

Fix: strip any `~`-prefixed key at every schema level, the same way `x-`
vendor extensions are already stripped -- this covers `~optional` and any
other Standard Schema metadata key the same libraries may emit, rather than
only patching this one literal key.

Testing: new regression test confirmed failing on unpatched code and
passing after the fix; full existing Gemini/schema-stripping test suite
(495 tests) still green.
hartmark added a commit to hartmark/OmniRoute that referenced this pull request Sep 20, 2026
…rd Schema keys from tool parameters) into dev/omniroute-dev-combined
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks @hartmark — merging via the release merge-train. Validated in local merge-train (mt-train10c) on the devbox @ train tip 4d841aa1c740bbaa03868dc0a403c62099a99a42 with the 72 sibling PRs of this batch: typecheck:core, file-size, complexity, cognitive-complexity, changelog-integrity green; changed-area node:test 831/831 (0 failing) and vitest 480/482 — the two reds are autoCombo/provider-family-combos.test.ts timing out at 20s, which reproduces on the PURE release tip under the full vitest suite (and is already tracked by the Release-Green issue #13866), so it is inherited, not this batch's. Merged --admin per merge-gates §3/§4/§7.

@diegosouzapw
diegosouzapw merged commit b9d4ea7 into diegosouzapw:release/v3.8.51 Sep 22, 2026
7 of 16 checks passed
@hartmark
hartmark deleted the fix/gemini-tilde-optional-schema-key branch September 22, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants