How to Raise Custom Errors
To manually trigger validation failures within custom validators, use PydanticCustomError for new error types or PydanticKnownError to reuse Pydantic's built-in error logic.
Raise a New Error Type with PydanticCustomError
Use PydanticCustomError when you need a specific error type and a custom message template. The message can include placeholders that are dynamically filled using a context dictionary.
from pydantic_core import PydanticCustomError, core_schema, SchemaValidator
def validate_even(input_value: int, info: core_schema.ValidationInfo) -> int:
if input_value % 2 != 0:
# 'not_even' is the error type slug
# {val} is a placeholder for the context value
raise PydanticCustomError(
'not_even',
'The value {val} is not even',
{'val': input_value}
)
return input_value
schema = core_schema.with_info_plain_validator_function(validate_even)
v = SchemaValidator(schema)
try:
v.validate_python(3)
except Exception as exc:
print(exc.errors())
# Output: [{'type': 'not_even', 'loc': (), 'msg': 'The value 3 is not even', 'input': 3, 'ctx': {'val': 3}}]
This pattern is used extensively in pydantic/types.py for specialized types like byte sizes:
# From pydantic/types.py
raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit})
Reuse Built-in Errors with PydanticKnownError
Use PydanticKnownError to trigger one of Pydantic's standard validation errors (e.g., greater_than, too_short, int_type). This ensures your custom validator remains consistent with Pydantic's internal error reporting and localization.
from pydantic_core import PydanticKnownError, core_schema, SchemaValidator
def validate_threshold(input_value: int, info: core_schema.ValidationInfo) -> int:
threshold = 42
if input_value <= threshold:
# Reuses the 'greater_than' error type and its standard message
raise PydanticKnownError('greater_than', {'gt': threshold})
return input_value
schema = core_schema.with_info_plain_validator_function(validate_threshold)
v = SchemaValidator(schema)
try:
v.validate_python(10)
except Exception as exc:
print(exc.errors())
# Output: [{'type': 'greater_than', 'loc': (), 'msg': 'Input should be greater than 42', 'input': 10, 'ctx': {'gt': 42}}]
Standard validators in pydantic/_internal/_validators.py use this to enforce constraints:
# From pydantic/_internal/_validators.py
if not (x > gt):
raise PydanticKnownError('greater_than', {'gt': _safe_repr(gt)})
Declarative Error Overrides with custom_error_schema
If you want a specific schema branch to always return a custom error upon failure without writing a full validator function, use core_schema.custom_error_schema. This wraps an existing schema and replaces any error it produces with your custom one.
from pydantic_core import core_schema, SchemaValidator
schema = core_schema.custom_error_schema(
core_schema.int_schema(),
custom_error_type='integer_required',
custom_error_message='Please provide a valid integer, you provided {input}',
custom_error_context={'input': 'invalid data'}
)
v = SchemaValidator(schema)
# Any non-integer input will now trigger 'integer_required' instead of 'int_type'
Usage in Different Validator Types
You can raise these errors in any validator function supported by pydantic-core.
Before Validator
Used to validate or transform raw input before it reaches the inner schema.
# From pydantic-core/tests/test_errors.py
def validator(input_value, info):
raise PydanticCustomError('my_error', 'my message with {val}', {'val': 42})
schema = core_schema.with_info_before_validator_function(
validator,
core_schema.int_schema()
)
Wrap Validator
Used when you need to control whether the inner validation runs at all, or if you want to catch its errors and re-raise them as custom ones.
# From pydantic/_internal/_validators.py
def sequence_validator(input_value, validator):
if isinstance(input_value, (str, bytes)):
raise PydanticCustomError(
'sequence_str',
"'{type_name}' instances are not allowed as a Sequence value",
{'type_name': type(input_value).__name__},
)
return validator(input_value)
Troubleshooting
- Context Key Mismatch: If you use a placeholder like
{val}in your message template but do not providevalin the context dictionary, the message will remain unformatted (e.g., "The value {val} is not even"). - Invalid Known Error Slug:
PydanticKnownErrorrequires a valid error type slug. Providing an unknown slug will result in aKeyErrorat runtime when the error is generated. - Catching Errors: These errors must be raised inside a validator function managed by a
SchemaValidator. If raised outside, they behave like standard Python exceptions and will not be collected into aValidationError. - Subclassing: You can subclass
PydanticCustomErrorto create domain-specific exceptions that still integrate with Pydantic's validation system.