Quickstart
Wire Errium into your app and see the difference in one request.
Pick your framework. Each one needs a single integration point. Django projects can add the Django helpers to cover errors raised outside the view layer.
Wire it up
main.py
from fastapi import FastAPI
import errium
app = FastAPI()
# Catches uncaught exceptions, HTTPException (incl. 404/405), and
# request validation errors.
errium.install(app)app.py
from flask import Flask
from errium_flask import ErriumFlask
app = Flask(__name__)
# Covers HTTP exceptions, uncaught exceptions, and pydantic validation errors.
ErriumFlask(app)api.py
from ninja import NinjaAPI
from errium_ninja import register_errium
api = NinjaAPI()
# Overrides Ninja's own handlers for ValidationError, HttpError,
# Http404, and Exception.
register_errium(api)settings.py
REST_FRAMEWORK = {
"EXCEPTION_HANDLER": "errium_drf.errium_exception_handler",
}See the difference
Post a request that fails validation — say a body missing its password field.
Without Errium, FastAPI hands back Pydantic’s raw output:
{
"detail": [
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": null
}
]
}With Errium, the same failure arrives in the standard contract:
{
"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."
}
}Every error your API returns now uses that shape, whether it came from a
validation failure, a 404, or an uncaught KeyError. Each one is also logged
on the errium logger with its trace_id, and the same ID comes back in an X-Trace-Id header — see Trace IDs.
Read the field-by-field contract on The response contract.