Exception Hierarchy
The application uses a custom exception hierarchy for domain-specific error handling.Base Exception Class
app/exceptions.py
- Consistent error response structure
- Optional additional payload for context
- HTTP status code mapping
- JSON serialization support
Domain-Specific Exceptions
ValidationError (400)
Raised when input data fails validation rules.app/exceptions.py
app/catalogs/colors/services.py
app/catalogs/unit_of_measures/services.py
NotFoundError (404)
Raised when a requested resource does not exist.app/exceptions.py
app/catalogs/colors/services.py
app/catalogs/wood_types/services.py
app/catalogs/unit_of_measures/services.py
ConflictError (409)
Raised when an operation conflicts with existing data (e.g., duplicate entries).app/exceptions.py
app/catalogs/colors/services.py
app/catalogs/roles/services.py
Error Response Format
All exceptions follow a consistent JSON structure:Basic Error Response
Error Response with Payload
Global Error Handlers
Error handlers are registered at the application level for consistent error responses.AppException Handler
app/exceptions.py
ValidationError, NotFoundError, and ConflictError exceptions.
Standard HTTP Error Handlers
app/exceptions.py
Error Handling Patterns
Pattern 1: Early Validation
- Fail fast on invalid input
- Avoid unnecessary database queries
- Clear error messages to clients
Pattern 2: Resource Existence Check
- Consistent error messages
- DRY principle (Don’t Repeat Yourself)
- Automatic NotFoundError propagation
Pattern 3: Uniqueness with Conflict Detection
- Proactive conflict detection
- Race condition protection
- Consistent error handling
Pattern 4: Transaction Rollback
- Maintains database consistency
- Prevents partial commits
- Allows retry after rollback
Exception Usage Summary
| Exception | Status Code | Use Case | Example |
|---|---|---|---|
ValidationError | 400 | Invalid or missing input | Empty name, missing required field |
NotFoundError | 404 | Resource doesn’t exist | Invalid ID, deleted record |
ConflictError | 409 | Duplicate or constraint violation | Duplicate name, IntegrityError |
AppException | 500 | Generic application error | Unexpected failures |
Error Logging
All AppExceptions are automatically logged:- Error type and message
- Stack trace for debugging
- Request context (automatic via Flask)
Best Practices
- Use Specific Exceptions: Prefer
ValidationError,NotFoundError,ConflictErrorover genericAppException - Include Context: Add entity name and identifier in error messages
- Always Rollback: Call
db.session.rollback()before re-raising after IntegrityError - Fail Fast: Validate input before expensive operations
- Consistent Messages: Use similar phrasing across services
- Reuse get_by_id: Let existing methods handle NotFoundError
- Log Appropriately: Let handlers log errors automatically
- Don’t Catch Without Re-raising: Always propagate or transform exceptions