produce errors you have to tell axum how to convert those errors into responses. ```rust use axum::{ Router, body::Body, http::{Request, Response, StatusCode}, error_handling::HandleError, }; async fn thing_that_might_fail() -> Result<(), anyhow::Error> { # Ok(()) // ... } // this service might fail with `anyhow::Error` let some_fallible_service = tower::service_fn(|_req| async { thing_that_might_fail().await?; Ok::<_, anyhow::Error>(Response::new(Body::empty())) }); let app = Router::new().route_service( "/", // we cannot route to `some_fallible_service` directly since it might fail. // we have to use `handle_error` which converts its errors into responses // and changes its error type from `anyhow::Error` to `Infallible`. HandleError::new(some_fallible_service, handle_anyhow_error), ); // handle errors by converting them into something that implements // `IntoResponse` async fn handle_anyhow_error(err: anyhow::Error) -> (StatusCode, String) { ( StatusCode::INTERNAL_SERVER_ERROR, format!("Something went wrong: {err}"), ) } # let _: Router = app; ``` # Applying fallible middleware Similarly axum requires you to handle errors from middleware. That is done with [`HandleErrorLayer`]: ```rust use axum::{ Router, BoxError, routing::get, http::StatusCode, error_handling::HandleErrorLayer, }; use std::time::Duration; use tower::ServiceBuilder; let app = Router::new() .route("/", get(|| async {})) .layer( ServiceBuilder::new() // `timeout` will produce an error if the handler takes // too long so we must handle those .layer(HandleErrorLayer::new(handle_timeout_error)) .timeout(Duration::from_secs(30)) ); async fn handle_timeout_error(err: BoxError) -> (StatusCode, String) { if err.is::() { ( StatusCode::REQUEST_TIMEOUT, "Request took too long".to_string(), ) } else { ( StatusCode::INTERNAL_SERVER_ERROR, format!("Unhandled internal error: {err}"), ) } } # let _: Router = app; ``` # Running extractors for error handling `HandleErrorLayer` also supports running extractors: ```rust use axum::{ Router, BoxError, routing::get, http::{StatusCode, Method, Uri}, error_handling::HandleErrorLayer, }; use std::time::Duration; use tower::ServiceBuilder; let app = Router::new() .route("/", get(|| async {})) .layer( ServiceBuilder::new() // `timeout` will produce an error if the handler takes // too long so we must handle those .layer(HandleErrorLayer::new(handle_timeout_error)) .timeout(Duration::from_secs(30)) ); async fn handle_timeout_error( // `Method` and `Uri` are extractors so they can be used here method: Method, uri: Uri, // the last argument must be the error itself err: BoxError, ) -> (StatusCode, String) { ( StatusCode::INTERNAL_SERVER_ERROR, format!("`{method} {uri}` failed with {err}"), ) } # let _: Router = app; ``` [`tower::Service`]: `tower::Service` [`Infallible`]: std::convert::Infallible [`Response`]: crate::response::Response [`IntoResponse`]: crate::response::IntoResponse