Understanding Validation Errors
In this codebase, validation errors are managed through the ValidationError exception, which provides a structured way to access and interpret failures that occur during data validation. When a BaseModel or TypeAdapter encounters data that does not conform to the defined schema, it raises a ValidationError containing one or more individual error details.
Catching and Inspecting Errors
The standard way to handle validation failures is to catch ValidationError in a try...except block. This exception is re-exported by pydantic but is fundamentally implemented in pydantic_core.
from pydantic import BaseModel, ValidationError
class UserModel(BaseModel):
username: str
try:
UserModel(username=123) # Invalid type
except ValidationError as e:
print(e.error_count()) # Returns the number of errors
print(e) # Prints a human-readable summary
The string representation of a ValidationError provides a clear summary of the location, message, and type for each error found.
Structured Error Data (ErrorDetails)
For programmatic processing, ValidationError provides the .errors() method, which returns a list of ErrorDetails. ErrorDetails is a TypedDict defined in pydantic_core/__init__.py with the following structure:
| Field | Type | Description |
|---|---|---|
type | str | A programmatic identifier for the error (e.g., string_type, less_than). |
loc | tuple[int | str, ...] | The path to the failing field. Strings represent keys, while integers represent list indices. |
msg | str | A human-readable error message. |
input | Any | The actual value that caused the validation to fail. |
ctx | dict[str, Any] | (Optional) Contextual values used to render the error message (e.g., the limit in a less_than error). |
url | str | (Optional) A link to the Pydantic documentation for that specific error type. |
Programmatic Access Methods
The ValidationError class provides two primary methods for extracting these details:
-
.errors(): Returns a list ofErrorDetailsdictionaries.include_url: Whether to include the documentation URL (defaultTrue).include_context: Whether to include thectxdictionary (defaultTrue).include_input: Whether to include theinputvalue (defaultTrue).
-
.json(): Returns a JSON string representation of the errors, accepting the same inclusion arguments as.errors(), plus anindentparameter.
# Example of accessing structured errors
errors = e.errors(include_url=False)
for error in errors:
print(f"Error at {error['loc']}: {error['msg']} (type={error['type']})")
Manual Error Creation (InitErrorDetails)
In advanced scenarios, such as custom validators or manual validation logic, you may need to raise a ValidationError yourself. This is done using the from_exception_data class method, which accepts a list of InitErrorDetails.
InitErrorDetails (defined in pydantic_core/__init__.py) is similar to ErrorDetails but allows the type to be either a string slug or a PydanticCustomError instance.
from pydantic_core import ValidationError, InitErrorDetails
def manual_check(value: int):
if value < 0:
raise ValidationError.from_exception_data(
title='ManualValidation',
line_errors=[
InitErrorDetails(
type='less_than',
loc=('my_field',),
input=value,
ctx={'limit': 0}
)
]
)
As seen in pydantic/main.py, this method is used internally to raise errors for frozen instances or fields:
# From pydantic/main.py
raise ValidationError.from_exception_data(
model_cls.__name__, [{'type': error_type, 'loc': (name,), 'input': value}]
)
Customization and Configuration
Environment Variables
The inclusion of documentation URLs in error messages can be controlled globally via the PYDANTIC_ERRORS_INCLUDE_URL environment variable. If set to false, URLs will be omitted from the default repr and str of the exception. Note that this must be set before the first ValidationError is created due to internal caching.
Subclassing ValidationError
You can subclass ValidationError to override its behavior, such as modifying the output of the .errors() method. This is demonstrated in pydantic-core/tests/test_custom_errors.py:
from typing_extensions import override
from pydantic_core import ValidationError, ErrorDetails
class CustomLocOverridesError(ValidationError):
@override
def errors(
self, *, include_url: bool = True, include_context: bool = True, include_input: bool = True
) -> list[ErrorDetails]:
errors = super().errors(
include_url=include_url, include_context=include_context, include_input=include_input
)
# Example: Strip the first element of the location tuple
return [{**error, 'loc': error['loc'][1:]} for error in errors]
TypeError Handling
In this version of Pydantic, TypeError raised inside a validator is no longer automatically converted to a ValidationError. If a validator raises a TypeError, it will bubble up and crash the validation process unless it is explicitly caught or wrapped into a PydanticCustomError.