Raising Custom Errors in Validators
To raise specific, well-formatted exceptions within custom validation functions, you can use PydanticCustomError for entirely new error types or PydanticKnownError to trigger built-in Pydantic errors.
Raising New Error Types with PydanticCustomError
Use PydanticCustomError when you need a unique error "slug" and a custom message template. This is common in specialized types like colors or network addresses.
from pydantic_core import PydanticCustomError
from pydantic import field_validator
class MyModel:
@field_validator('byte_size')
@classmethod
def validate_byte_size(cls, v: str) -> str:
# Example adapted from pydantic/types.py
if ' ' not in v:
raise PydanticCustomError(
'byte_size_unit',
'could not interpret byte unit: {unit}',
{'unit': v}
)
return v
Key Components:
- Type (Slug): A unique identifier for the error (e.g.,
'byte_size_unit'). - Message Template: A string that can include placeholders in curly braces (e.g.,
'{unit}'). - Context: A dictionary used to populate the placeholders in the message template.
Reusing Built-in Errors with PydanticKnownError
Use PydanticKnownError to leverage Pydantic's existing error templates and translations while performing your own validation logic.
import math
from typing import Any
from pydantic_core import PydanticKnownError
def forbid_inf_nan_check(x: Any) -> Any:
# Example from pydantic/_internal/_validators.py
if not math.isfinite(x):
raise PydanticKnownError('finite_number')
return x
def greater_than_validator(x: Any, gt: Any) -> Any:
# Example from pydantic/_internal/_validators.py
if not (x > gt):
raise PydanticKnownError('greater_than', {'gt': str(gt)})
return x
When using PydanticKnownError, you must provide a valid error type slug. If the built-in error requires context (like gt for greater_than), it must be provided in the context dictionary.
Declarative Error Overrides with CustomErrorSchema
You can also override errors at the schema level using core_schema.custom_error_schema. This wraps an existing schema and replaces any validation errors it produces with a single custom error.
from pydantic_core import SchemaValidator, core_schema
# Example from pydantic-core/python/pydantic_core/core_schema.py
schema = core_schema.custom_error_schema(
schema=core_schema.int_schema(),
custom_error_type='MyError',
custom_error_message='Value must be a valid integer',
)
v = SchemaValidator(schema)
# If validation fails, it will always raise 'MyError' with the specified message
Inspecting Available Error Types
To see all built-in error types and their required context, you can use list_all_errors(). This returns a list of ErrorTypeInfo dictionaries.
from pydantic_core import list_all_errors
all_errors = list_all_errors()
for error in all_errors[:2]:
print(f"Type: {error['type']}")
print(f"Template: {error['message_template_python']}")
print(f"Example Context: {error.get('example_context')}")
Important Considerations
Context Value Types
Values in the context dictionary for both PydanticCustomError and PydanticKnownError should be simple types: str, int, float, or Decimal. Using complex objects may lead to errors during message rendering.
As seen in pydantic/_internal/_validators.py, it is often safer to convert complex values to strings:
# From pydantic/_internal/_validators.py
def _safe_repr(v: Any) -> int | float | str:
if isinstance(v, (int, float, str)):
return v
return repr(v)
raise PydanticKnownError('greater_than', {'gt': _safe_repr(some_complex_object)})
Automatic Wrapping
When you raise these errors inside a validator function, pydantic-core automatically catches them and wraps them into a standard ValidationError. You do not need to catch and re-raise them yourself.