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.