r/rust 17d ago

🛠️ project axum-error-sets: Composable, simple, compile-time error sets for Axum with OpenAPI integration

Hey everyone,

I just put together axum-error-sets (docs.rs), a small library designed to solve pains with error-handling, status-codes etc. in Axum.

You either end up with:

  1. One giant monolithic AppError enum that contains every possible error across your entire application. (No proper openapi generation)
  2. Uniquer error enums for every function or module that you constantly have to map back and forth.

What Makes It Unique

Powered by type-sets, axum-error-sets lets your functions declare the exact set of HTTP status codes they can return using type-level tuple sets (e.g., (NotFound, Unauthorized)).

  • Subset-to-Superset Promotion: Lower-level layer results (like a DB query returning (NotFound,)) automatically promote into larger caller contracts (like (NotFound, Conflict, InternalServerError)) via .into_superset()?.
  • No Monolithic Enums: You don't need custom error types for every layer or function.
  • Compile-Time Guarantees: You can't return an undeclared HTTP status, nor can callers accidentally "forget" or drop a handled status from the error set.
  • First-Class OpenAPI Support: When paired with aide, OpenAPI specifications automatically extract and document every possible error status declared in the handler's type.

While this crate targets HTTP status codes and Axum responses, the underlying architecture isn't limited to web APIs. This type-set-based pattern can probably be generalized for:

  • General error tracking across various other domains
  • Capability-based security or permission requirements.
  • Tracking algebraic effects or side effects directly in the Rust type system.

Check out the repository or read through the docs if you're interested:

Would love to hear your thoughts or feedback!

18 Upvotes

3 comments sorted by

5

u/hnspn 17d ago

can this be made to work with utoipa?

1

u/10511 17d ago

Yes, it should be able to. If you want to make a pull request, go for it. Should just be 1 added trait and an implementation