agentscope-ai/agentscope · error · ValueError
Cannot safely sanitize Gemini schema with both a multi-type
Error message
Cannot safely sanitize Gemini schema with both a multi-type nullable type array and anyOf.
What it means
Gemini's API doesn't accept nullable type arrays, so agentscope's sanitizer converts them. When a schema has a multi-element type array containing 'null' AND an anyOf key simultaneously, there is no unambiguous conversion, so it raises ValueError rather than silently producing a wrong schema.
Source
Thrown at src/agentscope/model/_gemini/_model.py:87
schema = dict(schema)
# Gemini's Schema model does not support the JSON Schema dialect marker.
schema.pop("$schema", None)
# Gemini (and many third-party proxies) reject `null` as a standalone
# functionDeclaration property type. Some MCP servers emit
# {"type": "null"} directly (not wrapped in anyOf) for parameters that
# accept None — rewrite it to "object" so it round-trips through the API.
if _is_null_schema(schema):
schema["type"] = "object"
elif isinstance(schema.get("type"), list):
non_null_types = [v for v in schema["type"] if v != "null"]
if len(non_null_types) == 1:
schema["type"] = non_null_types[0]
elif non_null_types:
if "anyOf" in schema:
raise ValueError(
"Cannot safely sanitize Gemini schema with both a "
"multi-type nullable type array and anyOf.",
)
schema.pop("type")
schema["anyOf"] = [{"type": type_} for type_ in non_null_types]
else:
schema["type"] = "object"
# Remove additionalProperties — not supported by Gemini
schema.pop("additionalProperties", None)
# Convert `const` into an equivalent single-value `enum` — Gemini's
# Schema model does not support the `const` keyword.
if "const" in schema:
const_value = schema.pop("const")
schema.setdefault("enum", [const_value])
# Simplify anyOf that only differs by a null type, e.g. Optional[X]View on GitHub (pinned to e90f1c7592)
Solutions
- Restructure the schema: express nullability via anyOf alone (drop the type array), e.g. anyOf: [{type:'integer'},{type:'string'},{type:'null'}] — in Pydantic, avoid type arrays by using explicit Union anyOf-friendly modeling
- Simplify the field to a single non-null type or Optional[single_type] (Optional[Union[a,b]] often still works since single non-null type collapses)
- Pre-sanitize your JSON schema before passing it to the Gemini tool call
Example fix
# before
class Args(BaseModel):
value: Optional[Union[int, str]] = None # type: [int, str, null]
# after
class Args(BaseModel):
value: Union[int, str, None] = Field(None, json_schema_extra={'anyOf': [{'type': 'integer'}, {'type': 'string'}]})
# or simplify: value: Optional[str] = None Defensive patterns
Strategy: validation
Validate before calling
def sanitize(node):
if isinstance(node, dict):
t = node.get('type')
if isinstance(t, list) and len([x for x in t if x != 'null']) > 1 and 'anyOf' in node:
node.pop('type')
node['anyOf'] = [{'type': x} for x in t if x != 'null'] + node['anyOf']
for v in node.values():
sanitize(v)
elif isinstance(node, list):
for v in node:
sanitize(v) Type guard
def has_conflicting_nullable(node: dict) -> bool:
t = node.get('type')
return isinstance(t, list) and len([x for x in t if x != 'null']) > 1 and 'anyOf' in node Prevention
- Prefer Optional[single_type] over Optional[Union[...]] in tool schemas for Gemini
- Test tool schemas against Gemini before shipping
When it happens
Trigger: A Pydantic field like Union[int, str, None] rendered as type: ['integer','string','null'] combined with anyOf in the same schema node (common with nested Optional unions or custom serializers).
Common situations: Using Union[int, str, None] or Optional[Union[...]] fields with the Gemini model; complex nested models generated by other libs passed as tool parameters.
Related errors
- Unsupported source type: {type(source)}
- One or more tool calls raised an exception
- Input validation failed for tool '{tool_call.name}': {e.mess
- Invalid permission decision behavior: {decision.behavior}
- Model call failed after retries, but no exception was raised
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/27c0c1c8247b0df8.
Report an issue: GitHub.