Skip to main content

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:

FieldTypeDescription
typestrA programmatic identifier for the error (e.g., string_type, less_than).
loctuple[int | str, ...]The path to the failing field. Strings represent keys, while integers represent list indices.
msgstrA human-readable error message.
inputAnyThe actual value that caused the validation to fail.
ctxdict[str, Any](Optional) Contextual values used to render the error message (e.g., the limit in a less_than error).
urlstr(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:

  1. .errors(): Returns a list of ErrorDetails dictionaries.

    • include_url: Whether to include the documentation URL (default True).
    • include_context: Whether to include the ctx dictionary (default True).
    • include_input: Whether to include the input value (default True).
  2. .json(): Returns a JSON string representation of the errors, accepting the same inclusion arguments as .errors(), plus an indent parameter.

# 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.