0
# Error Handling and Utilities
1
2
Exception classes, warning system, and utility functions for advanced pydantic usage patterns.
3
4
## Capabilities
5
6
### Exception Classes
7
8
Pydantic-specific exception classes for handling validation and configuration errors.
9
10
```python { .api }
11
class ValidationError(ValueError):
12
"""
13
Raised when validation fails.
14
15
Contains detailed information about validation failures.
16
"""
17
18
def __init__(self, errors, model=PydanticUndefined):
19
"""
20
Initialize validation error.
21
22
Args:
23
errors: List of error dictionaries
24
model: Model class that failed validation
25
"""
26
27
def errors(self, *, include_url=True, include_context=True):
28
"""
29
Get list of error dictionaries.
30
31
Args:
32
include_url (bool): Include error documentation URLs
33
include_context (bool): Include error context
34
35
Returns:
36
list: List of error dictionaries
37
"""
38
39
def error_count(self):
40
"""
41
Get total number of errors.
42
43
Returns:
44
int: Number of validation errors
45
"""
46
47
@property
48
def title(self):
49
"""str: Error title based on model name"""
50
51
class PydanticUserError(TypeError):
52
"""
53
Raised when user makes an error in pydantic usage.
54
55
Indicates incorrect usage of pydantic APIs or configuration.
56
"""
57
58
class PydanticUndefinedAnnotation(AttributeError):
59
"""
60
Raised when a field annotation is undefined or cannot be resolved.
61
"""
62
63
class PydanticSchemaGenerationError(TypeError):
64
"""
65
Raised when JSON schema generation fails.
66
"""
67
68
class PydanticImportError(ImportError):
69
"""
70
Raised when required imports are missing for optional features.
71
"""
72
73
class PydanticInvalidForJsonSchema(TypeError):
74
"""
75
Raised when a type cannot be represented in JSON schema.
76
"""
77
```
78
79
### Warning Classes
80
81
Warning classes for deprecated features and potential issues.
82
83
```python { .api }
84
class PydanticDeprecatedSince20(UserWarning):
85
"""
86
Warning for features deprecated since pydantic v2.0.
87
"""
88
89
class PydanticExperimentalWarning(UserWarning):
90
"""
91
Warning for experimental features that may change.
92
"""
93
```
94
95
### Utility Functions
96
97
Utility functions for working with pydantic models and types.
98
99
```python { .api }
100
def __version__():
101
"""
102
Get pydantic version string.
103
104
Returns:
105
str: Version string (e.g., "2.11.7")
106
"""
107
108
def compiled():
109
"""
110
Check if pydantic is running with compiled extensions.
111
112
Returns:
113
bool: True if compiled extensions are available
114
"""
115
116
class PydanticUndefined:
117
"""
118
Sentinel value for undefined/missing values.
119
120
Used internally to distinguish between None and undefined.
121
"""
122
123
def parse_obj_as(type_, obj):
124
"""
125
Parse object as specified type (legacy function).
126
127
Args:
128
type_: Type to parse as
129
obj: Object to parse
130
131
Returns:
132
Parsed object
133
134
Note:
135
Deprecated: Use TypeAdapter.validate_python() instead
136
"""
137
138
def schema_of(type_, *, title='Generated schema'):
139
"""
140
Generate schema for type (legacy function).
141
142
Args:
143
type_: Type to generate schema for
144
title (str): Schema title
145
146
Returns:
147
dict: Type schema
148
149
Note:
150
Deprecated: Use TypeAdapter.json_schema() instead
151
"""
152
153
def schema_json_of(type_, *, title='Generated schema', indent=2):
154
"""
155
Generate JSON schema string for type (legacy function).
156
157
Args:
158
type_: Type to generate schema for
159
title (str): Schema title
160
indent (int): JSON indentation
161
162
Returns:
163
str: JSON schema string
164
165
Note:
166
Deprecated: Use TypeAdapter.json_schema() instead
167
"""
168
```
169
170
### Error Context and Formatting
171
172
Advanced error handling utilities for better error reporting.
173
174
```python { .api }
175
class ErrorWrapper:
176
"""
177
Wrapper for validation errors with additional context.
178
"""
179
180
def __init__(self, exc, loc):
181
"""
182
Initialize error wrapper.
183
184
Args:
185
exc: Exception to wrap
186
loc: Location tuple for the error
187
"""
188
189
def format_errors(errors, *, model_name=None):
190
"""
191
Format validation errors for display.
192
193
Args:
194
errors: List of error dictionaries
195
model_name (str): Model name for context
196
197
Returns:
198
str: Formatted error message
199
"""
200
```
201
202
## Usage Examples
203
204
### Handling ValidationError
205
206
```python
207
from pydantic import BaseModel, ValidationError, Field
208
from typing import List
209
210
class User(BaseModel):
211
id: int = Field(..., gt=0)
212
name: str = Field(..., min_length=1, max_length=50)
213
email: str = Field(..., regex=r'^[\w\.-]+@[\w\.-]+\.\w+$')
214
age: int = Field(..., ge=0, le=150)
215
216
# Handle validation errors
217
try:
218
invalid_user = User(
219
id=-1, # Invalid: must be > 0
220
name="", # Invalid: too short
221
email="invalid", # Invalid: bad format
222
age=200 # Invalid: too high
223
)
224
except ValidationError as e:
225
print(f"Validation failed with {e.error_count()} errors:")
226
227
for error in e.errors():
228
field = " -> ".join(str(loc) for loc in error['loc'])
229
message = error['msg']
230
value = error.get('input', 'N/A')
231
print(f" {field}: {message} (got: {value})")
232
233
# Output:
234
# Validation failed with 4 errors:
235
# id: Input should be greater than 0 (got: -1)
236
# name: String should have at least 1 character (got: )
237
# email: String should match pattern '^[\w\.-]+@[\w\.-]+\.\w+$' (got: invalid)
238
# age: Input should be less than or equal to 150 (got: 200)
239
```
240
241
### Custom Error Messages
242
243
```python
244
from pydantic import BaseModel, Field, field_validator, ValidationError
245
246
class Product(BaseModel):
247
name: str = Field(..., min_length=1, description="Product name")
248
price: float = Field(..., gt=0, description="Product price in USD")
249
category: str
250
251
@field_validator('category')
252
@classmethod
253
def validate_category(cls, v):
254
allowed = ['electronics', 'clothing', 'books', 'home']
255
if v.lower() not in allowed:
256
raise ValueError(f'Category must be one of: {", ".join(allowed)}')
257
return v.lower()
258
259
try:
260
product = Product(
261
name="",
262
price=-10,
263
category="invalid_category"
264
)
265
except ValidationError as e:
266
# Print detailed error information
267
for error in e.errors():
268
print(f"Field: {error['loc']}")
269
print(f"Error: {error['msg']}")
270
print(f"Type: {error['type']}")
271
if 'ctx' in error:
272
print(f"Context: {error['ctx']}")
273
print("---")
274
```
275
276
### Nested Validation Errors
277
278
```python
279
from pydantic import BaseModel, ValidationError
280
from typing import List
281
282
class Address(BaseModel):
283
street: str
284
city: str
285
zip_code: str = Field(..., regex=r'^\d{5}(-\d{4})?$')
286
287
class User(BaseModel):
288
name: str
289
addresses: List[Address]
290
291
try:
292
user_data = {
293
'name': 'John',
294
'addresses': [
295
{'street': '123 Main St', 'city': 'Anytown', 'zip_code': 'invalid'},
296
{'street': '', 'city': 'Other City', 'zip_code': '12345'}
297
]
298
}
299
user = User(**user_data)
300
except ValidationError as e:
301
for error in e.errors():
302
# Error location shows nested path
303
location = ' -> '.join(str(loc) for loc in error['loc'])
304
print(f"{location}: {error['msg']}")
305
306
# Output:
307
# addresses -> 0 -> zip_code: String should match pattern '^\d{5}(-\d{4})?$'
308
# addresses -> 1 -> street: String should have at least 1 character
309
```
310
311
### Error Context and URLs
312
313
```python
314
from pydantic import BaseModel, ValidationError, Field
315
316
class Config(BaseModel):
317
timeout: int = Field(..., ge=1, le=3600)
318
max_connections: int = Field(..., ge=1, le=1000)
319
320
try:
321
config = Config(timeout=0, max_connections=2000)
322
except ValidationError as e:
323
# Get errors with full context and URLs
324
for error in e.errors(include_url=True, include_context=True):
325
print(f"Field: {error['loc']}")
326
print(f"Error: {error['msg']}")
327
print(f"Input: {error['input']}")
328
329
# Show constraint context if available
330
if 'ctx' in error:
331
print(f"Constraints: {error['ctx']}")
332
333
# Show documentation URL if available
334
if 'url' in error:
335
print(f"Help: {error['url']}")
336
print("---")
337
```
338
339
### Using PydanticUserError
340
341
```python
342
from pydantic import BaseModel, Field, PydanticUserError
343
344
class MyModel(BaseModel):
345
value: int
346
347
@classmethod
348
def create_with_validation(cls, **kwargs):
349
"""Factory method with additional validation."""
350
351
# Check for deprecated usage patterns
352
if 'old_field' in kwargs:
353
raise PydanticUserError(
354
"The 'old_field' parameter is no longer supported. "
355
"Use 'value' instead."
356
)
357
358
return cls(**kwargs)
359
360
# This would raise PydanticUserError
361
try:
362
model = MyModel.create_with_validation(old_field=42)
363
except PydanticUserError as e:
364
print(f"Usage error: {e}")
365
```
366
367
### Checking for Compiled Extensions
368
369
```python
370
from pydantic import compiled
371
372
if compiled:
373
print("Pydantic is running with compiled Rust extensions for better performance")
374
else:
375
print("Pydantic is running in pure Python mode")
376
print("Consider installing with: pip install pydantic[email]")
377
```
378
379
### Custom Error Formatting
380
381
```python
382
from pydantic import BaseModel, ValidationError, Field
383
import json
384
385
class ErrorFormatter:
386
@staticmethod
387
def format_validation_error(error: ValidationError) -> dict:
388
"""Format ValidationError for API responses."""
389
formatted_errors = []
390
391
for err in error.errors():
392
formatted_errors.append({
393
'field': '.'.join(str(loc) for loc in err['loc']),
394
'message': err['msg'],
395
'type': err['type'],
396
'value': err.get('input')
397
})
398
399
return {
400
'error': 'validation_failed',
401
'message': f'Validation failed with {error.error_count()} errors',
402
'details': formatted_errors
403
}
404
405
class User(BaseModel):
406
email: str = Field(..., regex=r'^[\w\.-]+@[\w\.-]+\.\w+$')
407
age: int = Field(..., ge=0, le=150)
408
409
try:
410
user = User(email='invalid-email', age=-5)
411
except ValidationError as e:
412
error_response = ErrorFormatter.format_validation_error(e)
413
print(json.dumps(error_response, indent=2))
414
```
415
416
### Legacy Function Migration
417
418
```python
419
from pydantic import parse_obj_as, schema_of, TypeAdapter, ValidationError
420
from typing import List, Dict
421
422
# Old way (deprecated)
423
try:
424
result = parse_obj_as(List[int], ['1', '2', '3'])
425
schema = schema_of(List[int])
426
except Exception as e:
427
print(f"Legacy function error: {e}")
428
429
# New way (recommended)
430
adapter = TypeAdapter(List[int])
431
try:
432
result = adapter.validate_python(['1', '2', '3'])
433
schema = adapter.json_schema()
434
print(f"Result: {result}")
435
print(f"Schema keys: {list(schema.keys())}")
436
except ValidationError as e:
437
print(f"Validation error: {e}")
438
```