Skip to Content

Why have one custom exception base + per-domain subclasses?

Category: Observability & Tracing

Answer

One root exception lets you attach metadata once, render one JSON error response shape, and decide which exceptions are catchable by middleware vs which surface 500s. Per-domain subclasses (RepositoryError, ServiceError, RouterError) tag where it came from without try/except ladders.

Concrete examples from the fca project context

Example 1

class AppError(Exception): pass; class RepositoryError(AppError): pass.

Example 2

Middleware catches AppError -> JSON {error_code, message, request_id}; other exceptions -> 500.

Example 3

Adding fields (retry_after, severity) is centralized in the renderer.

Data flow / flow chart

raise RepositoryError("not found")
  middleware catches AppError -> JSON {error_code, ...}
  Other exceptions not caught -> 500 with trace_id

Takeaway

One exception tree + one renderer beats N try/excepts scattered across routes.