FastAPI has add_exception_handler(...) for global error handling, and it works — until the same exception needs different meanings depending on context: 404 in one route, 401 in another, 422 elsewhere. Global handlers don’t account for that, and the behavior isn’t visible on the route itself.
Local try/except or decorators help, but try/except duplicates logic, and decorators don’t expose possible responses to FastAPI — so they’re missing from OpenAPI. Manual responses={...} can drift from actual behavior.
📦 fastapi-error-map lets you declare error handling right in the route via error_map, and generates the OpenAPI schema from those declarations.
Basic usage
Import ErrorAwareRouter instead of APIRouter, and define error handling rules per endpoint.
router = ErrorAwareRouter()
@router.get(
"/stock",
error_map={
# Just return 401 with default JSON
# like {"error": "..."}
AuthorizationError: 401,
# Return 409 with custom response,
# and run a side effect (e.g. notify)
OutOfStockError: rule(
status=409,
translator=OutOfStockTranslator(),
on_error=notify,
),
},
)
def check_stock(user_id: int = 0) -> None:
if user_id == 0:
raise AuthorizationError
raise OutOfStockError("No items available.")
OpenAPI picks these responses up automatically from error_map:

Key features
- 🔄 Drop-in compatibility with
APIRouter— just replace and keep working. - 📜 Automatic OpenAPI generation from
error_map— no manualresponses={...}and no risk of drift. - 🛠 Custom rules via
rule(...)— define status, translator, and callback per exception. - ⚡ Error callbacks with
on_error— trigger logging, alerts, metrics, or any side effect before responding. - 🎯 Exact error type matching (no inheritance) — explicit and predictable behavior.
- 🚨 Strict mode: warns if an exception isn’t mapped (
warn_on_unmapped=True).
Install
pip install fastapi-error-map
Would love to hear what you think!
P.S. See it powering clean architecture example app:
👉 https://github.com/ivan-borovets/fastapi-clean-example
Top comments (0)