Skip to content

JSON Schema API Reference

Auto-generated API documentation for the jsonschema module.

jsonschema

JSON Schema flattening, sanitization & validation — zero dependencies, stdlib only.

Flatten complex JSON Schemas for LLM providers, and validate data instances against JSON Schema (Draft 2020-12 subset used by OpenAPI 3.x).

Part of zerodep: https://github.com/Oaklight/zerodep Copyright (c) 2026 Peng Ding. MIT License.

Flattening example::

>>> from jsonschema import flatten_schema
>>> schema = {
...     "type": "object",
...     "properties": {
...         "user": {"$ref": "#/$defs/User"},
...     },
...     "$defs": {
...         "User": {
...             "type": "object",
...             "properties": {"name": {"type": "string"}},
...         }
...     },
... }
>>> flatten_schema(schema)
{'type': 'object', 'properties': {'user': {'type': 'object', 'properties': {'name': {'type': 'string'}}}}}

Validation example::

>>> from jsonschema import schema_validate, iter_errors
>>> schema = {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]}
>>> schema_validate({"name": "Alice"}, schema)
>>> errors = iter_errors({}, schema)
>>> len(errors)
1

Supported validation keywords (Draft 2020-12 subset)::

type, enum, const,
minLength, maxLength, pattern,
minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf,
properties, required, additionalProperties, patternProperties,
minProperties, maxProperties,
items, prefixItems, minItems, maxItems, uniqueItems, contains,
allOf, anyOf, oneOf, not, if/then/else

Not implemented: dependentRequired, dependentSchemas, propertyNames, minContains, maxContains, format.

Note: OpenAPI 3.0 nullable: true is not handled by the validator. Use flatten_schema to convert nullable to type: [..., "null"] before validating, or write schemas using Draft 2020-12 type arrays.

Flattening pipeline::

resolve_refs  →  merge_allof  →  simplify_unions  →  sanitize

SchemaErrorDetail dataclass

A single JSON Schema validation error.

Attributes:

Name Type Description
path str

Dotted/bracketed path to the failing instance location.

schema_path str

Dotted path into the schema that triggered the error.

validator str

The JSON Schema keyword that failed.

message str

Human-readable error message.

Source code in jsonschema/jsonschema.py
@dataclasses.dataclass(frozen=True, slots=True)
class SchemaErrorDetail:
    """A single JSON Schema validation error.

    Attributes:
        path: Dotted/bracketed path to the failing instance location.
        schema_path: Dotted path into the schema that triggered the error.
        validator: The JSON Schema keyword that failed.
        message: Human-readable error message.
    """

    path: str
    schema_path: str
    validator: str
    message: str

SchemaValidationError

Bases: Exception

Raised when data validation against a JSON Schema fails.

Attributes:

Name Type Description
errors

List of all validation errors found.

Source code in jsonschema/jsonschema.py
class SchemaValidationError(Exception):
    """Raised when data validation against a JSON Schema fails.

    Attributes:
        errors: List of all validation errors found.
    """

    def __init__(self, errors: list[SchemaErrorDetail]) -> None:
        self.errors = errors
        msgs = "; ".join(e.message for e in errors[:5])
        if len(errors) > 5:
            msgs += f" ... and {len(errors) - 5} more"
        super().__init__(f"{len(errors)} schema validation error(s): {msgs}")

resolve_refs(schema)

Resolve all local $ref pointers and inline their targets.

Supports any JSON Pointer fragment (RFC 6901), including #/$defs/, #/definitions/, #/components/schemas/, etc. After resolution, $defs and definitions maps are removed.

Parameters:

Name Type Description Default
schema dict[str, Any]

A JSON Schema dict.

required

Returns:

Type Description
dict[str, Any]

A new dict with all $ref inlined and definition maps removed.

Source code in jsonschema/jsonschema.py
def resolve_refs(schema: dict[str, Any]) -> dict[str, Any]:
    """Resolve all local ``$ref`` pointers and inline their targets.

    Supports any JSON Pointer fragment (RFC 6901), including
    ``#/$defs/``, ``#/definitions/``, ``#/components/schemas/``, etc.
    After resolution, ``$defs`` and ``definitions`` maps are removed.

    Args:
        schema: A JSON Schema dict.

    Returns:
        A new dict with all ``$ref`` inlined and definition maps removed.
    """
    schema = copy.deepcopy(schema)
    result = _inline_refs(schema, schema)
    # Strip consumed definition maps.
    for key in _DEFS_KEYS:
        result.pop(key, None)
    return result

merge_allof(schema)

Deep-merge all allOf sub-schemas into single schemas.

Parameters:

Name Type Description Default
schema dict[str, Any]

A JSON Schema dict ($ref should be resolved first).

required

Returns:

Type Description
dict[str, Any]

A new dict with all allOf keywords resolved.

Source code in jsonschema/jsonschema.py
def merge_allof(schema: dict[str, Any]) -> dict[str, Any]:
    """Deep-merge all ``allOf`` sub-schemas into single schemas.

    Args:
        schema: A JSON Schema dict (``$ref`` should be resolved first).

    Returns:
        A new dict with all ``allOf`` keywords resolved.
    """
    return _walk_merge_allof(copy.deepcopy(schema))

simplify_unions(schema)

Simplify anyOf/oneOf constructs.

  • Nullable pattern [{type: T}, {type: null}] → {type: T, nullable: true}
  • Single-variant: unwrap.
  • Multi-variant with null: strip the {type: null} branch, keep remaining branches under the original keyword (anyOf or oneOf).

Parameters:

Name Type Description Default
schema dict[str, Any]

A JSON Schema dict.

required

Returns:

Type Description
dict[str, Any]

A new dict with anyOf/oneOf simplified.

Source code in jsonschema/jsonschema.py
def simplify_unions(schema: dict[str, Any]) -> dict[str, Any]:
    """Simplify ``anyOf``/``oneOf`` constructs.

    - Nullable pattern ``[{type: T}, {type: null}]`` → ``{type: T, nullable: true}``
    - Single-variant: unwrap.
    - Multi-variant with null: strip the ``{type: null}`` branch, keep remaining
      branches under the original keyword (``anyOf`` or ``oneOf``).

    Args:
        schema: A JSON Schema dict.

    Returns:
        A new dict with ``anyOf``/``oneOf`` simplified.
    """
    return _walk_simplify(copy.deepcopy(schema))

sanitize(schema, *, strip_keys=None)

Strip unsupported schema keywords and validate required arrays.

Parameters:

Name Type Description Default
schema dict[str, Any]

A JSON Schema dict.

required
strip_keys set[str] | None

Additional keys to strip beyond :data:UNSUPPORTED_SCHEMA_KEYS.

None

Returns:

Type Description
dict[str, Any]

A new dict with unsupported keys removed and required arrays

dict[str, Any]

pruned so that required ⊆ properties.keys() at every level.

Source code in jsonschema/jsonschema.py
def sanitize(
    schema: dict[str, Any],
    *,
    strip_keys: set[str] | None = None,
) -> dict[str, Any]:
    """Strip unsupported schema keywords and validate ``required`` arrays.

    Args:
        schema: A JSON Schema dict.
        strip_keys: Additional keys to strip beyond
            :data:`UNSUPPORTED_SCHEMA_KEYS`.

    Returns:
        A new dict with unsupported keys removed and ``required`` arrays
        pruned so that ``required ⊆ properties.keys()`` at every level.
    """
    strip = UNSUPPORTED_SCHEMA_KEYS | (strip_keys or set())
    return _walk_sanitize(copy.deepcopy(schema), strip)

flatten_schema(schema, *, strip_keys=None)

One-call full pipeline: resolve → merge → simplify → sanitize.

Parameters:

Name Type Description Default
schema dict[str, Any]

A JSON Schema dict, possibly containing $ref, allOf, anyOf, oneOf, and unsupported keywords.

required
strip_keys set[str] | None

Additional keys to strip beyond :data:UNSUPPORTED_SCHEMA_KEYS.

None

Returns:

Type Description
dict[str, Any]

A flattened, sanitized schema safe for LLM provider consumption.

Source code in jsonschema/jsonschema.py
def flatten_schema(
    schema: dict[str, Any],
    *,
    strip_keys: set[str] | None = None,
) -> dict[str, Any]:
    """One-call full pipeline: resolve → merge → simplify → sanitize.

    Args:
        schema: A JSON Schema dict, possibly containing ``$ref``,
            ``allOf``, ``anyOf``, ``oneOf``, and unsupported keywords.
        strip_keys: Additional keys to strip beyond
            :data:`UNSUPPORTED_SCHEMA_KEYS`.

    Returns:
        A flattened, sanitized schema safe for LLM provider consumption.
    """
    result = resolve_refs(schema)
    result = _walk_merge_allof(result)  # skip redundant deepcopy
    result = _walk_simplify(result)
    strip = UNSUPPORTED_SCHEMA_KEYS | (strip_keys or set())
    result = _walk_sanitize(result, strip)
    return result

iter_errors(instance, schema, *, resolved=False)

Validate instance against JSON Schema schema and return all errors.

The schema is preprocessed: $ref pointers are resolved before validation. Composition keywords (allOf, anyOf, oneOf, not) are evaluated semantically, not merged.

When validating many instances against the same schema, resolve once and pass resolved=True to skip redundant $ref resolution::

schema = resolve_refs(raw_schema)
for item in items:
    errors = iter_errors(item, schema, resolved=True)

Parameters:

Name Type Description Default
instance Any

The data to validate.

required
schema dict[str, Any] | bool

A JSON Schema dict, or a boolean schema.

required
resolved bool

If True, skip $ref resolution (caller already called :func:resolve_refs). Defaults to False because passing an unresolved schema with resolved=True silently skips $ref targets — the validator would ignore them and report no errors for the referenced sub-schemas.

False

Returns:

Type Description
list[SchemaErrorDetail]

A list of :class:SchemaErrorDetail; empty if valid.

Source code in jsonschema/jsonschema.py
def iter_errors(
    instance: Any,
    schema: dict[str, Any] | bool,
    *,
    resolved: bool = False,
) -> list[SchemaErrorDetail]:
    """Validate *instance* against JSON Schema *schema* and return all errors.

    The schema is preprocessed: ``$ref`` pointers are resolved before
    validation.  Composition keywords (``allOf``, ``anyOf``, ``oneOf``,
    ``not``) are evaluated semantically, not merged.

    When validating many instances against the same schema, resolve once
    and pass ``resolved=True`` to skip redundant ``$ref`` resolution::

        schema = resolve_refs(raw_schema)
        for item in items:
            errors = iter_errors(item, schema, resolved=True)

    Args:
        instance: The data to validate.
        schema: A JSON Schema dict, or a boolean schema.
        resolved: If ``True``, skip ``$ref`` resolution (caller already
            called :func:`resolve_refs`).  Defaults to ``False`` because
            passing an unresolved schema with ``resolved=True`` silently
            skips ``$ref`` targets — the validator would ignore them and
            report no errors for the referenced sub-schemas.

    Returns:
        A list of :class:`SchemaErrorDetail`; empty if valid.
    """
    errors: list[SchemaErrorDetail] = []
    if isinstance(schema, bool):
        _validate_schema(instance, schema, errors, "", "")
        return errors
    effective = schema if resolved else resolve_refs(schema)
    _validate_schema(instance, effective, errors, "", "")
    return errors

schema_validate(instance, schema, *, resolved=False)

Validate instance against JSON Schema schema.

Parameters:

Name Type Description Default
instance Any

The data to validate.

required
schema dict[str, Any] | bool

A JSON Schema dict.

required
resolved bool

If True, skip $ref resolution (caller already called :func:resolve_refs). Must not be set to True unless the schema has been resolved — unresolved $ref nodes would be silently ignored.

False

Raises:

Type Description
SchemaValidationError

If validation fails, with all errors collected.

Source code in jsonschema/jsonschema.py
def schema_validate(
    instance: Any,
    schema: dict[str, Any] | bool,
    *,
    resolved: bool = False,
) -> None:
    """Validate *instance* against JSON Schema *schema*.

    Args:
        instance: The data to validate.
        schema: A JSON Schema dict.
        resolved: If ``True``, skip ``$ref`` resolution (caller already
            called :func:`resolve_refs`).  Must not be set to ``True``
            unless the schema has been resolved — unresolved ``$ref``
            nodes would be silently ignored.

    Raises:
        SchemaValidationError: If validation fails, with all errors collected.
    """
    errors = iter_errors(instance, schema, resolved=resolved)
    if errors:
        raise SchemaValidationError(errors)