Introduction
What Errium does, and the problem it solves.
Errium is a lightweight error normalization and translation library for Python APIs. It intercepts uncaught exceptions, HTTP exceptions, and request validation errors, and standardizes them into a single consistent, frontend-safe JSON response shape.
It supports four frameworks today — FastAPI, Flask, Django Ninja, and Django
REST Framework — through a framework-agnostic core (errium_core) plus one
thin adapter package per framework, and a small set of Django helpers for errors raised outside the view layer.
The problem
Modern API frameworks yield inconsistent error responses, and the cost lands on whoever consumes them.
- Validation errors are hard to read. Pydantic’s output is deeply nested and
verbose. A single missing field arrives as a list of objects with
loc,type,msgandinputkeys that the client has to walk before it can show anything useful. - Backend responses disagree with each other. An uncaught internal exception might leak a stack trace or return plain text, depending on where in the request lifecycle it was raised.
- Every service needs its own parser. Frontend engineers write bespoke error-handling for each microservice, because no two of them shape errors the same way.
The solution
Errium runs every error through one pipeline, in four stages.
- Intelligent middleware.
errium.install(app)— or the equivalent entry point for your framework — transparently intercepts the request lifecycle. - Classification.
ClassificationEngineresolves the error’s category, status code, and user-facing message by running it past an ordered list of classifiers. - Beautification and normalization. Nested, complex validation errors
collapse into a flat
{field: message}map. - Environment-aware sanitization. Full tracebacks in development, sealed internals in production — switched by a single environment variable.
Every handled exception is also logged with its trace_id, so the ID a client
reports leads straight to the traceback.
The result is that every error your API returns looks the same, no matter what threw it:
{
"success": false,
"status_code": 422,
"code": "VALIDATION_ERROR",
"message": "Validation failed.",
"trace_id": "87b003a8-7c15-4a6c-9c76-a05b22b109e2",
"timestamp": "2026-05-27T12:00:00Z",
"details": {
"password": "Password is required."
}
}Ready to wire it up? Start with the Quickstart.