zylon-ai/private-gpt · error · ValueError

Array 'items' must be a dictionary representing JSON Schema

Error message

Array 'items' must be a dictionary representing JSON Schema

What it means

Raised by _validate_json_schema_item when an array schema's "items" value is not a dict. JSON Schema requires items to be a schema object; this validator enforces dict form because it recursively builds Pydantic models from it. Tuples, lists (per-item form), or strings like "string" all trigger it.

Source

Thrown at private_gpt/chat/schema_models.py:125

    if "allOf" in schema:
        if not isinstance(schema["allOf"], list):
            raise ValueError("'allOf' must be an array of schemas")
        for sub_schema in schema["allOf"]:
            _validate_json_schema_item(sub_schema, strict=False)
        return  # allOf schemas don't need type field

    # Regular schema validation
    if "type" not in schema:
        if strict:
            raise ValueError("Schema must define a 'type' field")
        else:
            return  # Non-strict mode allows missing type

    if schema["type"] == "array" and "items" not in schema:
        raise ValueError("Array schemas must define 'items'")

    if schema["type"] == "array" and not isinstance(schema.get("items"), dict):
        raise ValueError("Array 'items' must be a dictionary representing JSON Schema")

    # Recursively validate array items
    if schema["type"] == "array":
        _validate_json_schema_item(schema.get("items", {}))


def _validate_json_schema(schema: dict[str, Any]) -> None:
    """Validate that the schema is a valid JSON Schema object."""
    if not isinstance(schema, dict):
        raise ValueError("Schema must be a dictionary representing JSON Schema")
    if not schema:
        return

    # Composition keywords at the top level are valid without a "type" field.
    for composition_key in ("allOf", "anyOf", "oneOf"):
        if composition_key in schema:
            for sub_schema in schema[composition_key]:
                _validate_json_schema_item(sub_schema, strict=False)

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Wrap the item type in a schema object: {"items": {"type": "string"}} instead of {"items": "string"}.
  2. Replace tuple-form items arrays with {"items": {"anyOf": [ ... ]}}.
  3. If items comes from user input, coerce/validate it to a dict before calling the API.

Example fix

// before
{"type": "array", "items": "string"}

// after
{"type": "array", "items": {"type": "string"}}
Defensive patterns

Strategy: validation

Validate before calling

def coerce_items(node: dict) -> None:
    if node.get("type") == "array":
        items = node.get("items")
        if isinstance(items, str):
            node["items"] = {"type": items}
        elif isinstance(items, list):
            node["items"] = {"anyOf": items}
        if not isinstance(node.get("items"), dict):
            raise ValueError(f"Bad items for array: {items!r}")

Type guard

def has_dict_items(s: dict) -> bool:
    return s.get("type") != "array" or isinstance(s.get("items"), dict)

Try / catch

try:
    create_model_from_json_schema(schema)
except ValueError as e:
    raise HTTPException(400, detail=str(e)) from e

Prevention

When it happens

Trigger: Passing {"type": "array", "items": "string"} (type as a bare string), {"items": [ {"type": "string"}, {"type": "number"} ]} (tuple-validation array form), or items set to None within a schema sent to create_model_from_json_schema.

Common situations: Translating from Python type hints or OpenAPI specs where item types are strings; using the legacy JSON Schema array-form items; YAML configs where items collapses to a scalar.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/50a731817b5ed36a. Report an issue: GitHub.