0
# Error Handling
1
2
Comprehensive error handling system with detailed error information, location tracking, and support for custom error messages and error type definitions. Pydantic Core provides rich error reporting that helps developers understand validation failures.
3
4
## Capabilities
5
6
### Main Exception Classes
7
8
Core exception classes for different types of validation and serialization errors.
9
10
```python { .api }
11
class ValidationError(ValueError):
12
"""
13
Main validation error with detailed error information.
14
15
Raised when data validation fails, containing detailed information
16
about what went wrong, where it went wrong, and the context.
17
"""
18
19
def errors(self) -> list[ErrorDetails]:
20
"""
21
Get detailed information about all validation errors.
22
23
Returns:
24
List of error details with location, message, and context
25
"""
26
27
def error_count(self) -> int:
28
"""
29
Get the total number of validation errors.
30
31
Returns:
32
Number of errors
33
"""
34
35
def __str__(self) -> str:
36
"""
37
Get a human-readable error message.
38
39
Returns:
40
Formatted error message
41
"""
42
43
class PydanticCustomError(ValueError):
44
"""
45
Custom validation error with user-defined messages.
46
47
Allows developers to create validation errors with custom
48
error types and message templates.
49
"""
50
51
def __init__(self, error_type: str, message_template: str, context: dict = None):
52
"""
53
Create a custom validation error.
54
55
Args:
56
error_type: String identifier for the error type
57
message_template: Template string for the error message
58
context: Context values for message template formatting
59
"""
60
61
class PydanticKnownError(ValueError):
62
"""
63
Pre-defined validation error for known error types.
64
65
Used for standard validation errors with pre-defined
66
error types and message templates.
67
"""
68
69
def __init__(self, error_type: ErrorType, context: dict = None):
70
"""
71
Create a known validation error.
72
73
Args:
74
error_type: Pre-defined error type
75
context: Context values for message formatting
76
"""
77
78
class SchemaError(Exception):
79
"""
80
Schema definition and building errors.
81
82
Raised when there are problems with schema definitions,
83
such as invalid schema structures or conflicting constraints.
84
"""
85
86
class PydanticSerializationError(ValueError):
87
"""
88
Serialization process errors.
89
90
Raised when data cannot be serialized due to unsupported
91
types or serialization constraints.
92
"""
93
94
class PydanticSerializationUnexpectedValue(PydanticSerializationError):
95
"""
96
Unexpected value during serialization.
97
98
Raised when the serializer encounters a value that doesn't
99
match the expected schema during serialization.
100
"""
101
```
102
103
### Error Information Structures
104
105
TypedDict structures that provide detailed error information.
106
107
```python { .api }
108
ErrorDetails = TypedDict('ErrorDetails', {
109
'type': str, # Error type identifier
110
'loc': tuple[int | str, ...], # Location tuple (field path)
111
'msg': str, # Human-readable error message
112
'input': Any, # The input value that caused the error
113
'ctx': NotRequired[dict[str, Any]], # Additional error context
114
'url': NotRequired[str] # Documentation URL for the error
115
})
116
117
InitErrorDetails = TypedDict('InitErrorDetails', {
118
'type': Union[str, PydanticCustomError], # Error type or custom error
119
'loc': NotRequired[tuple[int | str, ...]], # Location tuple
120
'input': Any, # The input value that caused the error
121
'ctx': NotRequired[dict[str, Any]] # Additional error context
122
})
123
124
ErrorTypeInfo = TypedDict('ErrorTypeInfo', {
125
'type': ErrorType, # The error type
126
'message_template_python': str, # Message template for Python input
127
'example_message_python': str, # Example message for Python input
128
'message_template_json': NotRequired[str], # Message template for JSON input
129
'example_message_json': NotRequired[str], # Example message for JSON input
130
'example_context': dict[str, Any] | None # Example context values
131
})
132
```
133
134
### Error Type Constants
135
136
Pre-defined error types for common validation failures.
137
138
```python { .api }
139
ErrorType = Literal[
140
# General validation errors
141
'missing', 'extra_forbidden', 'value_error', 'assertion_error', 'type_error',
142
143
# Boolean validation errors
144
'bool_parsing', 'bool_type',
145
146
# Integer validation errors
147
'int_parsing', 'int_type', 'int_parsing_size', 'int_from_float',
148
'int_greater_than', 'int_greater_than_equal', 'int_less_than',
149
'int_less_than_equal', 'int_multiple_of',
150
151
# Float validation errors
152
'float_parsing', 'float_type', 'float_finite_number',
153
'float_greater_than', 'float_greater_than_equal', 'float_less_than',
154
'float_less_than_equal', 'float_multiple_of',
155
156
# String validation errors
157
'string_type', 'string_too_short', 'string_too_long', 'string_pattern_mismatch',
158
'string_unicode', 'string_sub_type',
159
160
# Bytes validation errors
161
'bytes_type', 'bytes_too_short', 'bytes_too_long',
162
163
# Date and time validation errors
164
'date_parsing', 'date_type', 'date_future', 'date_past',
165
'time_parsing', 'time_type',
166
'datetime_parsing', 'datetime_type', 'datetime_future', 'datetime_past',
167
'datetime_aware', 'datetime_naive',
168
'timedelta_parsing', 'timedelta_type',
169
'timezone_naive', 'timezone_aware',
170
171
# Collection validation errors
172
'list_type', 'tuple_type', 'set_type', 'frozenset_type', 'dict_type',
173
'too_short', 'too_long',
174
175
# Advanced type validation errors
176
'is_instance_of', 'is_subclass_of', 'callable_type',
177
'literal_error', 'enum_parsing',
178
'union_tag_invalid', 'union_tag_not_found',
179
180
# URL validation errors
181
'url_parsing', 'url_syntax_violation', 'url_too_long', 'url_scheme',
182
183
# UUID validation errors
184
'uuid_parsing', 'uuid_version',
185
186
# Decimal validation errors
187
'decimal_parsing', 'decimal_type', 'decimal_max_digits',
188
'decimal_max_places', 'decimal_whole_digits',
189
190
# JSON validation errors
191
'json_invalid', 'json_type',
192
193
# Model validation errors
194
'model_type', 'model_attributes_type', 'model_class',
195
'dataclass_type', 'dataclass_exact_type',
196
197
# Custom and function validation errors
198
'custom_error', 'validator_error', 'function_no_validator',
199
'function_after_field_validator', 'function_before_field_validator',
200
'function_wrap_validator', 'function_plain_validator',
201
202
# And many more...
203
]
204
```
205
206
### Utility Functions
207
208
Functions for working with error information.
209
210
```python { .api }
211
def list_all_errors() -> list[ErrorTypeInfo]:
212
"""
213
Get information about all possible validation error types.
214
215
Returns:
216
List of error type information including message templates and examples
217
"""
218
```
219
220
## Usage Examples
221
222
### Basic Error Handling
223
224
```python
225
from pydantic_core import SchemaValidator, ValidationError
226
from pydantic_core.core_schema import dict_schema, str_schema, int_schema
227
228
# Create a schema
229
schema = dict_schema({
230
'name': str_schema(min_length=2),
231
'age': int_schema(ge=0, le=120),
232
'email': str_schema()
233
})
234
235
validator = SchemaValidator(schema)
236
237
# Try to validate invalid data
238
try:
239
invalid_data = {
240
'name': 'A', # Too short
241
'age': 150, # Too high
242
'email': '' # Empty string
243
}
244
validator.validate_python(invalid_data)
245
except ValidationError as e:
246
print(f"Validation failed with {e.error_count()} errors:")
247
248
for error in e.errors():
249
location = ' -> '.join(map(str, error['loc']))
250
print(f" {location}: {error['msg']}")
251
print(f" Input: {error['input']}")
252
print(f" Type: {error['type']}")
253
if 'ctx' in error:
254
print(f" Context: {error['ctx']}")
255
print()
256
257
# Output:
258
# Validation failed with 3 errors:
259
# name: String should have at least 2 characters
260
# Input: A
261
# Type: string_too_short
262
# Context: {'min_length': 2}
263
#
264
# age: Input should be less than or equal to 120
265
# Input: 150
266
# Type: int_less_than_equal
267
# Context: {'le': 120}
268
#
269
# email: String should have at least 1 character
270
# Input:
271
# Type: string_too_short
272
# Context: {'min_length': 1}
273
```
274
275
### Nested Data Error Locations
276
277
```python
278
from pydantic_core import SchemaValidator, ValidationError
279
from pydantic_core.core_schema import dict_schema, list_schema, str_schema, int_schema
280
281
# Schema for nested data
282
schema = dict_schema({
283
'users': list_schema(
284
dict_schema({
285
'name': str_schema(min_length=1),
286
'age': int_schema(ge=0)
287
})
288
)
289
})
290
291
validator = SchemaValidator(schema)
292
293
try:
294
data = {
295
'users': [
296
{'name': 'Alice', 'age': 25}, # Valid
297
{'name': '', 'age': -5}, # Invalid name and age
298
{'name': 'Charlie', 'age': 30} # Valid
299
]
300
}
301
validator.validate_python(data)
302
except ValidationError as e:
303
for error in e.errors():
304
# Location shows exact path to error
305
location_path = ' -> '.join(map(str, error['loc']))
306
print(f"{location_path}: {error['msg']}")
307
308
# Output:
309
# users -> 1 -> name: String should have at least 1 character
310
# users -> 1 -> age: Input should be greater than or equal to 0
311
```
312
313
### Custom Error Messages
314
315
```python
316
from pydantic_core import PydanticCustomError, SchemaValidator, ValidationError
317
from pydantic_core.core_schema import with_info_plain_validator_function
318
319
def validate_username(value):
320
"""Custom validator with custom error messages."""
321
if not isinstance(value, str):
322
raise PydanticCustomError(
323
'username_type',
324
'Username must be a string, got {input_type}',
325
{'input_type': type(value).__name__}
326
)
327
328
if len(value) < 3:
329
raise PydanticCustomError(
330
'username_too_short',
331
'Username must be at least 3 characters long, got {input_length}',
332
{'input_length': len(value)}
333
)
334
335
if not value.isalnum():
336
raise PydanticCustomError(
337
'username_invalid_chars',
338
'Username must contain only letters and numbers'
339
)
340
341
return value
342
343
# Create schema with custom validator
344
schema = with_info_plain_validator_function(validate_username)
345
validator = SchemaValidator(schema)
346
347
try:
348
validator.validate_python('ab!') # Invalid characters
349
except ValidationError as e:
350
for error in e.errors():
351
print(f"Error: {error['msg']}")
352
print(f"Type: {error['type']}")
353
if 'ctx' in error:
354
print(f"Context: {error['ctx']}")
355
356
# Output:
357
# Error: Username must contain only letters and numbers
358
# Type: username_invalid_chars
359
```
360
361
### Known Error Types
362
363
```python
364
from pydantic_core import PydanticKnownError, SchemaValidator, ValidationError
365
from pydantic_core.core_schema import with_info_plain_validator_function
366
367
def validate_even_number(value):
368
"""Validator using known error types."""
369
if not isinstance(value, int):
370
raise PydanticKnownError('int_type')
371
372
if value % 2 != 0:
373
raise PydanticKnownError(
374
'int_multiple_of',
375
{'multiple_of': 2}
376
)
377
378
return value
379
380
schema = with_info_plain_validator_function(validate_even_number)
381
validator = SchemaValidator(schema)
382
383
try:
384
validator.validate_python(7) # Odd number
385
except ValidationError as e:
386
for error in e.errors():
387
print(f"Error: {error['msg']}")
388
print(f"Type: {error['type']}")
389
print(f"Context: {error.get('ctx', {})}")
390
391
# Output will use the standard int_multiple_of error message
392
```
393
394
### Serialization Error Handling
395
396
```python
397
from pydantic_core import (
398
SchemaSerializer,
399
PydanticSerializationError,
400
PydanticSerializationUnexpectedValue
401
)
402
from pydantic_core.core_schema import dict_schema, str_schema
403
404
# Create serializer
405
schema = dict_schema({'name': str_schema()})
406
serializer = SchemaSerializer(schema)
407
408
try:
409
# Try to serialize invalid data structure
410
invalid_data = {'name': object()} # object() is not serializable
411
serializer.to_json(invalid_data)
412
except PydanticSerializationError as e:
413
print(f"Serialization error: {e}")
414
415
# Handle with fallback
416
def fallback_handler(obj):
417
return str(obj)
418
419
try:
420
result = serializer.to_json(
421
{'name': object()},
422
fallback=fallback_handler
423
)
424
print(f"Serialized with fallback: {result}")
425
except PydanticSerializationError as e:
426
print(f"Still failed: {e}")
427
```
428
429
### Working with Error Information
430
431
```python
432
from pydantic_core import list_all_errors
433
434
# Get information about all possible error types
435
all_errors = list_all_errors()
436
437
# Find specific error type information
438
string_errors = [
439
error for error in all_errors
440
if error['type'].startswith('string_')
441
]
442
443
for error_info in string_errors[:3]: # Show first 3 string errors
444
print(f"Type: {error_info['type']}")
445
print(f"Template: {error_info['message_template_python']}")
446
print(f"Example: {error_info['example_message_python']}")
447
if error_info['example_context']:
448
print(f"Context: {error_info['example_context']}")
449
print()
450
451
# Output shows error type information for string validation errors
452
```
453
454
### Error Filtering and Analysis
455
456
```python
457
from pydantic_core import SchemaValidator, ValidationError
458
from pydantic_core.core_schema import dict_schema, str_schema, int_schema, list_schema
459
460
# Complex schema for demonstration
461
schema = dict_schema({
462
'personal': dict_schema({
463
'name': str_schema(min_length=1),
464
'age': int_schema(ge=0, le=120)
465
}),
466
'contacts': list_schema(
467
dict_schema({
468
'type': str_schema(),
469
'value': str_schema(min_length=1)
470
})
471
)
472
})
473
474
validator = SchemaValidator(schema)
475
476
try:
477
data = {
478
'personal': {'name': '', 'age': -1},
479
'contacts': [
480
{'type': 'email', 'value': ''},
481
{'type': 'phone', 'value': 'valid-phone'}
482
]
483
}
484
validator.validate_python(data)
485
except ValidationError as e:
486
# Analyze errors by location
487
errors_by_section = {}
488
for error in e.errors():
489
section = error['loc'][0] if error['loc'] else 'root'
490
if section not in errors_by_section:
491
errors_by_section[section] = []
492
errors_by_section[section].append(error)
493
494
for section, errors in errors_by_section.items():
495
print(f"\nErrors in {section} section:")
496
for error in errors:
497
location = ' -> '.join(map(str, error['loc'][1:])) # Skip section name
498
print(f" {location}: {error['msg']}")
499
500
# Count errors by type
501
error_types = {}
502
for error in e.errors():
503
error_type = error['type']
504
error_types[error_type] = error_types.get(error_type, 0) + 1
505
506
print(f"\nError type distribution:")
507
for error_type, count in error_types.items():
508
print(f" {error_type}: {count}")
509
```