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

  1. 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
  2. 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)
  3. 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

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


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/27c0c1c8247b0df8. Report an issue: GitHub.