Errors, Cancellation, and Backpressure
Axum distinguishes failures that are valid HTTP outcomes from failures that would otherwise escape the service.
Rejections are responses
Missing path data, invalid JSON, and absent headers are expected request
failures. An extractor returns its rejection, and the handler adapter converts
it with IntoResponse. The handler is never called.
Application errors follow the same model when their error type implements
IntoResponse:
async fn handler() -> Result<Json<User>, ApiError> { /* ... */ }
This does not mean every internal error should be exposed. ApiError is the
policy boundary that logs private context and chooses a safe status and body.
Tower errors must be handled before serving
Axum’s top-level router has Error = Infallible, because Hyper needs every
request outcome to become a response. Middleware such as a generic Tower
timeout may produce an error. HandleErrorLayer maps that error asynchronously
to an IntoResponse, restoring the infallible outer contract.
Source: error_handling/mod.rs:115
Cancellation is usually dropping a future
If the peer disconnects and Hyper no longer needs the response, the request future may be dropped. Rust runs destructors for values currently owned by that future, but it does not roll back external effects.
- a database transaction guard can roll back on drop;
- a spawned child task may continue unless explicitly cancelled;
- an already-sent email or payment cannot be unsent;
- a multi-step mutation needs idempotency or a durable workflow boundary.
Cancellation safety is a property of each awaited operation, not a blanket guarantee supplied by Axum.
Readiness is deliberately subtle
Routing needs the request before it knows the destination. Axum therefore keeps routers always ready and drives destination readiness inside the returned future. A backpressure-sensitive service should be wrapped with an explicit load-shed, buffer, or limit policy—or placed around the entire router.
Source: middleware documentation
Graceful shutdown is a drain protocol
On shutdown, the server stops accepting new connections and signals connection tasks to begin Hyper’s graceful shutdown. A Tokio watch channel also accounts for live connection tasks. The server waits until their receivers are dropped.
Graceful does not imply bounded. A handler awaiting forever prevents complete drain, so production applications pair graceful shutdown with request or drain deadlines.
Source: serve/mod.rs:450