Error Handling#
Panther converts APIError exceptions into HTTP responses. Unknown exceptions are logged and returned as 500 Internal Server Error.
Error classes live in panther.exceptions.
APIError#
Use APIError when you need a custom API error.
from panther import status
from panther.exceptions import APIError
async def endpoint():
raise APIError(
detail={'detail': 'Something went wrong'},
status_code=status.HTTP_400_BAD_REQUEST,
headers={'X-Error-Code': 'example'},
)
Panther returns:
detailas response data.status_codeas the HTTP status.headersas response headers.
If detail is a string, Panther wraps it as {'detail': detail}.
Built-In API Errors#
| Exception | Status | Default detail |
|---|---|---|
APIError |
500 | Internal Server Error |
BadRequestAPIError |
400 | Bad Request |
AuthenticationAPIError |
401 | Authentication Error |
AuthorizationAPIError |
403 | Permission Denied |
NotFoundAPIError |
404 | Not Found |
MethodNotAllowedAPIError |
405 | Method Not Allowed |
UnprocessableEntityError |
422 | Unprocessable Entity Error |
UpgradeRequiredError |
426 | This service requires use of the WebSocket protocol. |
ThrottlingAPIError |
429 | Too Many Request |
Example:
from panther.exceptions import BadRequestAPIError
async def create_item():
raise BadRequestAPIError(detail='Name is required')
Not Found#
For database models, find_one_or_raise raises NotFoundAPIError.
from app.models import Book
async def get_book(book_id: str):
return await Book.find_one_or_raise(id=book_id)
Pass filters as keyword arguments or dictionaries. Do not pass a raw ID string positionally.
Authentication And Authorization#
Use AuthenticationAPIError for invalid credentials.
from panther.exceptions import AuthenticationAPIError
class ApiKeyAuthentication:
async def __call__(self, request):
if request.headers['x-api-key'] != 'secret':
raise AuthenticationAPIError
return {'username': 'admin'}
Use permissions for authorization checks. Returning False from a permission causes AuthorizationAPIError.
class IsAdmin:
async def __call__(self, request):
return bool(request.user and request.user.get('is_admin'))
Validation Errors#
When input_model validation fails, Panther returns BadRequestAPIError.
from pydantic import BaseModel, Field
from panther.app import API
from panther.request import Request
class CreateBookInput(BaseModel):
title: str = Field(min_length=1)
@API(methods=['POST'], input_model=CreateBookInput)
async def create_book(request: Request):
return request.validated_data.model_dump()
Invalid JSON raises UnprocessableEntityError.
Preserving APIError Status Codes#
When catching broad exceptions, re-raise APIError before converting unknown exceptions to 500.
from panther import status
from panther.exceptions import APIError
async def upload_file():
try:
raise APIError('File too large', status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE)
except APIError:
raise
except Exception as e:
raise APIError(
detail=f'Upload failed: {e}',
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
Without the except APIError: raise branch, intentional API errors can be accidentally converted into 500 responses.
RedirectAPIError#
RedirectAPIError is an exception-based redirect helper.
from panther.exceptions import RedirectAPIError
async def old_endpoint():
raise RedirectAPIError('/new-endpoint/')
For normal endpoint code, prefer RedirectResponse when returning a redirect is clearer.
WebSocket Errors#
WebsocketError is the base WebSocket error class. WebSocket close codes are available in panther.status.
from panther import status
from panther.websocket import close_websocket_connection
async def close_connection(connection_id: str):
await close_websocket_connection(
connection_id=connection_id,
code=status.WS_1008_POLICY_VIOLATION,
reason='Policy violation',
)
Framework And Database Errors#
PantherError and DatabaseError are internal/setup-level errors. They are not regular API response helpers:
PantherErroris used for invalid configuration, routing, imports, and setup.DatabaseErroris used by database/query internals.
Use APIError subclasses for user-facing endpoint errors.