Skip to main content

Sentinel and Special-Purpose Schemas

Sentinel and special-purpose schemas in pydantic-core provide the foundation for handling non-standard types, nullability, and internal state management. Unlike standard type schemas (like IntSchema or StringSchema), these schemas define how the validator should treat None, missing values, or catch-all scenarios.

Handling Nullability​

Pydantic distinguishes between a schema that only accepts None and a schema that allows a value to be either a specific type or None.

None Schema​

The NoneSchema (created via core_schema.none_schema()) is a strict validator that only accepts the Python None value. It is defined in pydantic-core/python/pydantic_core/core_schema.py.

from pydantic_core import SchemaValidator, core_schema

# Only None is allowed
schema = core_schema.none_schema()
v = SchemaValidator(schema)

assert v.validate_python(None) is None
# v.validate_python(1) would raise a ValidationError

Nullable Schema​

The NullableSchema is a wrapper used to implement Optional types. It takes an inner schema and allows the input to be either None or a value that satisfies the inner schema.

from pydantic_core import SchemaValidator, core_schema

# Allows a string OR None
schema = core_schema.nullable_schema(core_schema.str_schema())
v = SchemaValidator(schema)

assert v.validate_python("hello") == "hello"
assert v.validate_python(None) is None

The NullableSchema also supports a strict flag, which determines if the underlying schema should be validated in strict mode.

The Catch-All: Any Schema​

The AnySchema is used when a field should accept any Python object without validation. It is frequently used as a fallback or for dynamic data where the structure is unknown.

from pydantic_core import SchemaValidator, core_schema

schema = core_schema.any_schema()
v = SchemaValidator(schema)

assert v.validate_python(1) == 1
assert v.validate_python({"key": "value"}) == {"key": "value"}
assert v.validate_python(None) is None

In pydantic-core, AnySchema is often the default return_schema for serializers when no specific type information is available.

Internal Sentinels and Error States​

Some schemas are designed for internal coordination or to mark specific states during schema construction.

Missing Sentinel Schema​

The MissingSentinelSchema is used to represent the MISSING state. This is distinct from None, as it typically represents a value that was not provided at all (e.g., a missing key in a dictionary).

from pydantic_core import core_schema

# Represents the internal MISSING sentinel
schema = core_schema.missing_sentinel_schema()

Invalid Schema​

The InvalidSchema acts as a placeholder. It is not intended to be used for actual validation. If a SchemaValidator is initialized with an InvalidSchema, it will raise a SchemaError. This is useful for marking incomplete definitions or states that should never be reached in a valid schema tree.

As seen in pydantic-core/tests/test_schema_functions.py:

import pytest
from pydantic_core import SchemaValidator, core_schema, SchemaError

def test_err_on_invalid():
# Attempting to use an invalid schema raises a SchemaError
with pytest.raises(SchemaError, match='Cannot construct schema with `InvalidSchema` member.'):
SchemaValidator(core_schema.invalid_schema())

Comparison Summary​

SchemaType LiteralPurpose
NoneSchema'none'Matches only None.
NullableSchema'nullable'Wraps another schema to allow None.
AnySchema'any'Matches any value.
MissingSentinelSchema'missing-sentinel'Matches the internal MISSING sentinel.
InvalidSchema'invalid'Placeholder that triggers SchemaError on use.