You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
nullable enums reach Gemini via OpenCode as the string "null" #369
Found by the 3.0.0 pre-release host smoke test (#301).
Since #300 (piece A of #236), optional enum arguments advertise null as an enum member, e.g. refresh.source: {"enum": ["claude_config","custom",null], "type": ["string","null"]}. Four enums are affected on main: catalog_search.filters.risk_max, refresh.source, set_startup_policy.source, sync_environment.platform.
OpenCode 1.18.34's Google provider rewrites schemas for Gemini. Every type: [X,"null"] becomes anyOf: [{"type": X}] (null dropped), and null inside an enum becomes the string"null" (captured request: "enum": ["claude_config","custom","null"]). A Gemini model can then send source: "null", which pmcp would likely refuse. Whether the real Gemini API accepts the rewritten payload was not verified (no Gemini key on the test host).
Options
Leave null out of enum and rely on the type array (null is still accepted through the type), or emit anyOf: [{"enum":[...]},{"type":"null"}]. Check against each host family's schema conversion, and add a schema test that no enum contains null. This is likely a small fix; it could go in a 3.0.x.
The plan is merged as b9bf9d3 (#370). All four review seats agreed on rev 2.
It covers:
Every nullable argument is advertised as anyOf: [X, {"type": "null"}]. null never appears in an enum, const, default or type array.
gate_error_for keeps the 3.0 gate's messages, paths and audit fields identical. A re-fuzz of about 115k multi-error calls found 0 differences.
OpenCode's Google path now sends {type: X, nullable: true} and no "null" strings, verified against the real 1.18.34 binary.
Next is the implementation PR, built from the proven spike. It also takes the two review nits: the fallback will cover the final ranking, and the CHANGELOG clause order will be fixed. The aim is to land it before the 3.0.0 tag.
Fixed in 23edd92 (#371), which lands before the 3.0.0 tag.
All 42 nullable arguments are now advertised as anyOf: [X, {"type": "null"}], and null no longer appears in any enum, const, default or type array. OpenCode's Google provider now sends {type: X, nullable: true}, with no "null" strings.
The gate's behaviour is unchanged: it accepts and refuses the same calls and reports the same message, keyword and path as 3.0. A fuzz of about 115k calls found 0 differences. Enum messages no longer list None.
Still unverified: live acceptance by the native Gemini API. agy can't be tested because of #368, which rejects dotted tool names.
Activity
docs(plan): rev 2 -- rebased on b8e4305; unfold nullable refusals bef…
docs(plan): nullable arguments as anyOf [X, {type: null}], never null…
ViperJuice commentedon Oct 5, 2026
The plan is merged as b9bf9d3 (#370). All four review seats agreed on rev 2.
It covers:
anyOf: [X, {"type": "null"}].nullnever appears in anenum,const,defaultortypearray.gate_error_forkeeps the 3.0 gate's messages, paths and audit fields identical. A re-fuzz of about 115k multi-error calls found 0 differences.{type: X, nullable: true}and no"null"strings, verified against the real 1.18.34 binary.Next is the implementation PR, built from the proven spike. It also takes the two review nits: the fallback will cover the final ranking, and the CHANGELOG clause order will be fixed. The aim is to land it before the 3.0.0 tag.
schema: nullable arguments as anyOf [X, {type: null}]; gate reports u…
ViperJuice commentedon Oct 5, 2026
Fixed in 23edd92 (#371), which lands before the 3.0.0 tag.
All 42 nullable arguments are now advertised as
anyOf: [X, {"type": "null"}], andnullno longer appears in anyenum,const,defaultortypearray. OpenCode's Google provider now sends{type: X, nullable: true}, with no"null"strings.The gate's behaviour is unchanged: it accepts and refuses the same calls and reports the same message, keyword and path as 3.0. A fuzz of about 115k calls found 0 differences. Enum messages no longer list
None.Still unverified: live acceptance by the native Gemini API. agy can't be tested because of #368, which rejects dotted tool names.