0
# Error Handling
1
2
Comprehensive exception hierarchy for handling configuration errors, database operational errors, integrity constraints, validation failures, and query-related exceptions. Tortoise ORM provides specific exceptions for different error scenarios to enable proper error handling and debugging.
3
4
## Capabilities
5
6
### Exception Hierarchy
7
8
Base exception classes and their inheritance structure.
9
10
```python { .api }
11
class BaseORMException(Exception):
12
"""
13
Base ORM exception class.
14
15
All Tortoise ORM exceptions inherit from this base class.
16
"""
17
18
class ConfigurationError(BaseORMException):
19
"""
20
Configuration error exception.
21
22
Raised when there are issues with Tortoise ORM configuration,
23
such as invalid database settings, missing models, or incorrect
24
field definitions.
25
"""
26
27
class FieldError(BaseORMException):
28
"""
29
Field definition error exception.
30
31
Raised when there is a problem with model field definitions,
32
such as invalid field types, incorrect field options, or
33
conflicting field configurations.
34
"""
35
36
class ParamsError(BaseORMException):
37
"""
38
Parameter error exception.
39
40
Raised when functions cannot be executed with the provided
41
parameters, such as invalid query parameters or incorrect
42
function arguments.
43
"""
44
45
class TransactionManagementError(BaseORMException):
46
"""
47
Transaction management error exception.
48
49
Raised when there are issues with database transaction
50
management, such as nested transaction conflicts or
51
transaction state errors.
52
"""
53
```
54
55
### Database Operation Exceptions
56
57
Exceptions related to database operations and constraints.
58
59
```python { .api }
60
class OperationalError(BaseORMException):
61
"""
62
Database operational error exception.
63
64
Raised when database operations fail due to operational
65
issues such as connection problems, query execution errors,
66
or database-specific errors.
67
"""
68
69
class IntegrityError(OperationalError):
70
"""
71
Database integrity constraint violation exception.
72
73
Raised when database operations violate integrity constraints
74
such as unique constraints, foreign key constraints, or
75
check constraints.
76
"""
77
78
class ValidationError(BaseORMException):
79
"""
80
Model validation error exception.
81
82
Raised when model field validation fails, such as invalid
83
field values, constraint violations, or custom validation
84
errors.
85
"""
86
```
87
88
### Query-Related Exceptions
89
90
Exceptions specific to query operations and results.
91
92
```python { .api }
93
class DoesNotExist(BaseORMException):
94
"""
95
Object does not exist exception.
96
97
Raised when a query expects to find a single object but
98
no matching object exists in the database.
99
"""
100
101
class MultipleObjectsReturned(BaseORMException):
102
"""
103
Multiple objects returned exception.
104
105
Raised when a query expects to find a single object but
106
multiple matching objects exist in the database.
107
"""
108
109
class ObjectDoesNotExistError(BaseORMException):
110
"""
111
Object does not exist error exception.
112
113
Alternative exception for cases where objects are expected
114
to exist but are not found.
115
"""
116
117
class IncompleteInstanceError(BaseORMException):
118
"""
119
Incomplete model instance error exception.
120
121
Raised when trying to perform operations on model instances
122
that are missing required data or are in an incomplete state.
123
"""
124
```
125
126
## Usage Examples
127
128
### Configuration Error Handling
129
130
```python
131
from tortoise import Tortoise
132
from tortoise.exceptions import ConfigurationError
133
134
async def setup_database():
135
try:
136
await Tortoise.init(
137
config={
138
'connections': {
139
'default': 'invalid://connection/string'
140
},
141
'apps': {
142
'models': {
143
'models': ['nonexistent.models'],
144
}
145
}
146
}
147
)
148
except ConfigurationError as e:
149
print(f"Configuration error: {e}")
150
# Handle configuration errors
151
# - Check database connection string
152
# - Verify model module paths
153
# - Validate configuration structure
154
```
155
156
### Database Operation Error Handling
157
158
```python
159
from tortoise.exceptions import IntegrityError, OperationalError
160
161
class User(Model):
162
id = fields.IntField(pk=True)
163
email = fields.CharField(max_length=100, unique=True)
164
name = fields.CharField(max_length=50)
165
166
async def create_user(email, name):
167
try:
168
user = await User.create(email=email, name=name)
169
return user
170
except IntegrityError as e:
171
print(f"Integrity constraint violated: {e}")
172
# Handle constraint violations
173
# - Unique constraint violations
174
# - Foreign key constraint violations
175
# - Check constraint violations
176
raise ValueError("Email already exists")
177
except OperationalError as e:
178
print(f"Database operation failed: {e}")
179
# Handle operational errors
180
# - Connection timeouts
181
# - Database locks
182
# - Query execution errors
183
raise RuntimeError("Database temporarily unavailable")
184
```
185
186
### Query Error Handling
187
188
```python
189
from tortoise.exceptions import DoesNotExist, MultipleObjectsReturned
190
191
async def get_user_by_email(email):
192
try:
193
user = await User.get(email=email)
194
return user
195
except DoesNotExist:
196
print(f"No user found with email: {email}")
197
return None
198
except MultipleObjectsReturned:
199
print(f"Multiple users found with email: {email}")
200
# This shouldn't happen with unique email field
201
# but could occur with non-unique fields
202
users = await User.filter(email=email).all()
203
return users[0] # Return first one or handle differently
204
205
async def get_user_by_id(user_id):
206
try:
207
user = await User.get(id=user_id)
208
return user
209
except DoesNotExist:
210
raise ValueError(f"User with ID {user_id} not found")
211
```
212
213
### Validation Error Handling
214
215
```python
216
from tortoise.exceptions import ValidationError
217
218
class Product(Model):
219
id = fields.IntField(pk=True)
220
name = fields.CharField(max_length=100)
221
price = fields.DecimalField(max_digits=10, decimal_places=2)
222
223
def clean(self):
224
if self.price < 0:
225
raise ValidationError("Price cannot be negative")
226
227
async def create_product(name, price):
228
try:
229
product = Product(name=name, price=price)
230
await product.full_clean() # Run validation
231
await product.save()
232
return product
233
except ValidationError as e:
234
print(f"Validation failed: {e}")
235
# Handle validation errors
236
# - Invalid field values
237
# - Custom validation failures
238
# - Field constraint violations
239
raise ValueError(f"Invalid product data: {e}")
240
```
241
242
### Transaction Error Handling
243
244
```python
245
from tortoise.exceptions import TransactionManagementError
246
from tortoise.transactions import in_transaction
247
248
async def transfer_money(from_account, to_account, amount):
249
try:
250
async with in_transaction():
251
# Debit from source account
252
from_account.balance -= amount
253
await from_account.save()
254
255
# Credit to target account
256
to_account.balance += amount
257
await to_account.save()
258
259
except TransactionManagementError as e:
260
print(f"Transaction failed: {e}")
261
# Handle transaction errors
262
# - Deadlocks
263
# - Transaction conflicts
264
# - Rollback failures
265
raise RuntimeError("Money transfer failed")
266
except Exception as e:
267
print(f"Unexpected error during transaction: {e}")
268
# Transaction will be automatically rolled back
269
raise
270
```
271
272
### Comprehensive Error Handling
273
274
```python
275
from tortoise.exceptions import (
276
BaseORMException, ConfigurationError, FieldError,
277
OperationalError, IntegrityError, ValidationError,
278
DoesNotExist, MultipleObjectsReturned
279
)
280
281
class UserService:
282
@staticmethod
283
async def create_user(email, name, age=None):
284
try:
285
# Validate input
286
if not email or '@' not in email:
287
raise ValidationError("Invalid email address")
288
289
if not name or len(name.strip()) == 0:
290
raise ValidationError("Name is required")
291
292
# Create user
293
user = await User.create(
294
email=email.lower().strip(),
295
name=name.strip(),
296
age=age
297
)
298
return user
299
300
except ValidationError as e:
301
# Re-raise validation errors with context
302
raise ValueError(f"User validation failed: {e}")
303
304
except IntegrityError as e:
305
# Handle database constraint violations
306
if "unique" in str(e).lower():
307
raise ValueError("Email address already exists")
308
else:
309
raise ValueError("User data violates database constraints")
310
311
except OperationalError as e:
312
# Handle database operational errors
313
raise RuntimeError(f"Database error during user creation: {e}")
314
315
except BaseORMException as e:
316
# Catch any other ORM-specific errors
317
raise RuntimeError(f"ORM error: {e}")
318
319
@staticmethod
320
async def get_user(user_id=None, email=None):
321
try:
322
if user_id:
323
return await User.get(id=user_id)
324
elif email:
325
return await User.get(email=email)
326
else:
327
raise ParamsError("Either user_id or email must be provided")
328
329
except DoesNotExist:
330
return None
331
332
except MultipleObjectsReturned:
333
# This shouldn't happen with unique fields
334
raise RuntimeError("Data integrity issue: multiple users found")
335
336
except ParamsError as e:
337
raise ValueError(str(e))
338
339
@staticmethod
340
async def update_user(user_id, **updates):
341
try:
342
user = await User.get(id=user_id)
343
344
# Apply updates
345
for field, value in updates.items():
346
if hasattr(user, field):
347
setattr(user, field, value)
348
else:
349
raise FieldError(f"Unknown field: {field}")
350
351
await user.save()
352
return user
353
354
except DoesNotExist:
355
raise ValueError(f"User with ID {user_id} not found")
356
357
except FieldError as e:
358
raise ValueError(str(e))
359
360
except ValidationError as e:
361
raise ValueError(f"Update validation failed: {e}")
362
363
except IntegrityError as e:
364
raise ValueError(f"Update violates constraints: {e}")
365
```
366
367
### Error Logging and Monitoring
368
369
```python
370
import logging
371
from tortoise.exceptions import BaseORMException
372
373
logger = logging.getLogger(__name__)
374
375
async def safe_database_operation(operation_func, *args, **kwargs):
376
"""Wrapper for safe database operations with logging."""
377
try:
378
return await operation_func(*args, **kwargs)
379
380
except ConfigurationError as e:
381
logger.error(f"Database configuration error: {e}")
382
raise
383
384
except IntegrityError as e:
385
logger.warning(f"Data integrity violation: {e}")
386
raise
387
388
except OperationalError as e:
389
logger.error(f"Database operational error: {e}")
390
raise
391
392
except DoesNotExist as e:
393
logger.info(f"Object not found: {e}")
394
raise
395
396
except ValidationError as e:
397
logger.warning(f"Validation error: {e}")
398
raise
399
400
except BaseORMException as e:
401
logger.error(f"Unexpected ORM error: {e}")
402
raise
403
404
except Exception as e:
405
logger.error(f"Unexpected error in database operation: {e}")
406
raise
407
408
# Usage
409
result = await safe_database_operation(User.create, email="test@example.com", name="Test User")
410
```
411
412
### Web Framework Error Handling
413
414
```python
415
from fastapi import HTTPException, status
416
from tortoise.exceptions import DoesNotExist, IntegrityError, ValidationError
417
418
async def get_user_endpoint(user_id: int):
419
try:
420
user = await User.get(id=user_id)
421
return user
422
except DoesNotExist:
423
raise HTTPException(
424
status_code=status.HTTP_404_NOT_FOUND,
425
detail="User not found"
426
)
427
428
async def create_user_endpoint(user_data: dict):
429
try:
430
user = await User.create(**user_data)
431
return user
432
except ValidationError as e:
433
raise HTTPException(
434
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
435
detail=f"Validation error: {e}"
436
)
437
except IntegrityError as e:
438
raise HTTPException(
439
status_code=status.HTTP_409_CONFLICT,
440
detail="User with this email already exists"
441
)
442
```