run-llama/llama_index · error · ValueError

Unknown schema type {schema_type}

Error message

Unknown schema type {schema_type}

What it means

The final else branch of json_schema_to_guidance_output_template: the schema node's 'type' is not one of object/array/string/integer/number/boolean, so the walker has no guidance command to emit and raises ValueError(f"Unknown schema type {schema_type}"). Values like 'null', 'any', or missing/type-less nodes (e.g. pydantic v2 anyOf/Optional unions collapsed by .model_json_schema()) land here.

Source

Thrown at llama-index-core/llama_index/core/prompts/guidance_utils.py:125

        )
    elif schema["type"] == "string":
        if key is None:
            raise ValueError("key should not be None")
        return "\"{{gen '" + key + "' stop='\"'}}\""
    elif schema["type"] in ["integer", "number"]:
        if key is None:
            raise ValueError("key should not be None")
        if use_pattern_control:
            return "{{gen '" + key + "' pattern='[0-9\\.]' stop=','}}"
        else:
            return "\"{{gen '" + key + "' stop='\"'}}\""
    elif schema["type"] == "boolean":
        if key is None:
            raise ValueError("key should not be None")
        return "{{#select '" + key + "'}}True{{or}}False{{/select}}"
    else:
        schema_type = schema["type"]
        raise ValueError(f"Unknown schema type {schema_type}")


Model = TypeVar("Model", bound=BaseModel)


def parse_pydantic_from_guidance_program(
    response: str, cls: Type[Model], verbose: bool = False
) -> Model:
    """
    Parse output from guidance program.

    This is a temporary solution for parsing a pydantic object out of an executed
    guidance program.

    NOTE: right now we assume the output is the last markdown formatted json block

    NOTE: a better way is to extract via Program.variables, but guidance does not
          support extracting nested objects right now.

View on GitHub (pinned to afd0fef371)

Solutions

  1. Flatten the model: replace Optional/Union fields with a single concrete type (or str with a validator), so every node has a literal 'type' in its schema.
  2. Remove Any-typed and None-default fields that serialize as typeless/anyOf nodes.
  3. If the union is genuinely needed, move the guidance program to an object model with simple fields and do the union parsing in your own pydantic validator after extraction.
  4. Migrate off the guidance integration to a maintained structured-output path (provider JSON mode / function calling).

Example fix

// before
from typing import Optional, Union
from pydantic import BaseModel
class Info(BaseModel):
    value: Optional[int] = None      # anyOf -> no 'type' -> Unknown schema type
    tag: Union[str, int] | None = None

// after
from pydantic import BaseModel, field_validator
class Info(BaseModel):
    value: int = 0                   # concrete type; default replaces None
    tag: str = ""                    # single type; coerce in a validator if needed
    @field_validator("tag", mode="before")
    @classmethod
    def _cast(cls, v):
        return str(v)
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_TYPES = {"object", "array", "string", "integer", "number", "boolean"}

def assert_schema_types_supported(cls) -> None:
    schema = cls.model_json_schema()
    stack = [schema]
    while stack:
        node = stack.pop()
        if isinstance(node, dict):
            if "type" in node and node["type"] not in SUPPORTED_TYPES:
                raise TypeError(f"Unsupported schema type {node['type']!r} in {cls.__name__}")
            if "anyOf" in node or "allOf" in node or "$ref" in node:
                raise TypeError(
                    f"{cls.__name__} contains anyOf/allOf/$ref nodes; "
                    "flatten Optional/Union fields to single concrete types."
                )
            stack.extend(v for v in node.values() if isinstance(v, (dict, list)))
        elif isinstance(node, list):
            stack.extend(node)

assert_schema_types_supported(Info)

Type guard

def is_flat_guidance_schema(cls) -> bool:
    """True when every schema node carries a supported literal 'type'."""
    stack = [cls.model_json_schema()]
    while stack:
        node = stack.pop()
        if isinstance(node, dict):
            if node.get("type") not in SUPPORTED_TYPES and "type" in node:
                return False
            if any(k in node for k in ("anyOf", "allOf", "$ref")):
                return False
            stack.extend(v for v in node.values() if isinstance(v, (dict, list)))
        elif isinstance(node, list):
            stack.extend(node)
    return True

Prevention

When it happens

Trigger: Passing a pydantic model to GuidancePydanticProgram where some field's JSON schema has no plain 'type': Optional[...] rendered as anyOf, Union types, Any-typed fields, null-typed fields, or a hand-written JSON schema using '$ref'/'allOf' that the walker does not resolve.

Common situations: Pydantic v2 migrations (Optional fields now emit anyOf instead of a nullable type), models with Union or Any fields, or schemas imported from FastAPI/OpenAPI specs. The guidance utility is a shallow schema compiler and only understands a flat type field.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/5385a9e20790cb80. Report an issue: GitHub.