Add unified RequestValidationError handler to unify error response schema

- Add RequestValidationError handler that converts Pydantic validation errors to unified ErrorResponse format
- Ensures all error responses return consistent schema: code, detail, metadata, correlation_id
- Add field_errors count and first_field location to metadata for validation errors
- Register handler in exception handler hierarchy before HTTPException handler
- Add comprehensive tests for validation error responses
- Update Backend-Development.md documentation to include correlation_id field and validation error details
- All 44 error-related tests pass (38 existing + 6 new validation tests)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-01 15:49:39 +02:00
parent 0221e423f2
commit 4f7316c484
4 changed files with 243 additions and 48 deletions

View File

@@ -632,14 +632,16 @@ Every non-2xx HTTP response body is a JSON object with this structure:
"detail": "Jail 'example' not found",
"metadata": {
"jail_name": "example"
}
},
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
**Fields:**
- **`code`** (string, required): Machine-readable error code for client-side branching. Examples: `jail_not_found`, `rate_limit_exceeded`, `authentication_required`.
- **`code`** (string, required): Machine-readable error code for client-side branching. Examples: `jail_not_found`, `rate_limit_exceeded`, `authentication_required`, `invalid_input`.
- **`detail`** (string, required): Human-readable error message. Safe for displaying to users.
- **`metadata`** (object, optional): Structured context data relevant to the error. Only includes data safe for client consumption (no sensitive internal state). Examples: offending parameter names, resource identifiers, time windows.
- **`metadata`** (object, optional): Structured context data relevant to the error. Only includes data safe for client consumption (no sensitive internal state). Examples: offending parameter names, resource identifiers, field error counts, time windows.
- **`correlation_id`** (string | null, optional): Unique request ID for tracing this error across logs and systems. Set by the `CorrelationIdMiddleware`. Use this to correlate client-side errors with server logs for debugging.
### Exception Hierarchy & Error Codes
@@ -655,6 +657,8 @@ All domain exceptions inherit from `DomainError` (defined in `backend/app/except
| **401** | `AuthenticationError` | `authentication_required` | Authentication or authorization failure, invalid/expired credentials |
| **429** | `RateLimitError` | `rate_limit_exceeded` | Rate limit exceeded, too many requests |
**Note on request validation errors:** Pydantic validation errors (from request body type mismatches, missing required fields, etc.) are automatically caught by the `_request_validation_error_handler` and converted to `ErrorResponse` with `code="invalid_input"`. The `metadata` field includes `field_errors` (count of validation failures) and `first_field` (location of the first error field) to help clients debug malformed requests.
### Implementing Error Handlers
Every exception category has a corresponding exception handler registered in `backend/app/main.py`. When a domain exception is raised: