Search code examples
rustcompiler-errorsrust-axum

Why does my axum handler not implement Handler?


Every one of these handler functions below fail with essentially the exact same error "Handler is not satisfied":

use axum::{extract::Request, http::HeaderMap, routing::get, Json, Router};

fn routes() -> Router {
    Router::new()
        .route("/a", get(foo_a))
        .route("/b", get(foo_b))
        .route("/c", get(foo_c))
        .route("/d", get(foo_d))
        .route("/e", get(foo_e))
        .route("/f", get(foo_f))
}

struct MyExtractor;
struct MyResponse;
struct MyBody;

async fn foo_a(_: MyExtractor) -> &'static str {
    "hello world!"
}

async fn foo_b() -> MyResponse {
    MyResponse
}

async fn foo_c(body: Json<MyBody>) -> Json<MyBody> {
    body
}

async fn foo_d(_req: Request, _body: String) -> &'static str {
    "yum food"
}

async fn foo_e() -> &'static str {
    static LIST: std::sync::Mutex<Vec<i32>> = std::sync::Mutex::new(Vec::new());

    let _list = LIST.lock().unwrap();
    let _ = foo_b().await;
    drop(_list);

    "checked it twice"
}

async fn foo_f(_body: String, _headers: HeaderMap) -> &'static str {
    "foofy"
}
error[E0277]: the trait bound `fn(MyExtractor) -> impl Future<Output = &'static str> {foo_a}: Handler<_, _>` is not satisfied
   --> src/main.rs:5:26
    |
5   |         .route("/a", get(foo_a))
    |                      --- ^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(MyExtractor) -> impl Future<Output = &'static str> {foo_a}`
    |                      |
    |                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `axum::routing::get`
   --> /home/kmdreko/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.5/src/routing/method_routing.rs:385:1
    |
385 | top_level_handler_fn!(get, GET);
    | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `get`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `fn() -> impl Future<Output = MyResponse> {foo_b}: Handler<_, _>` is not satisfied
   --> src/main.rs:6:26
    |
6   |         .route("/b", get(foo_b))
    |                      --- ^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn() -> impl Future<Output = MyResponse> {foo_b}`
    |                      |
    |                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `axum::routing::get`
   --> /home/kmdreko/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.5/src/routing/method_routing.rs:385:1
    |
385 | top_level_handler_fn!(get, GET);
    | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `get`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `fn(Json<MyBody>) -> impl Future<Output = Json<MyBody>> {foo_c}: Handler<_, _>` is not satisfied
   --> src/main.rs:7:26
    |
7   |         .route("/c", get(foo_c))
    |                      --- ^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(Json<MyBody>) -> impl Future<Output = Json<MyBody>> {foo_c}`
    |                      |
    |                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `axum::routing::get`
   --> /home/kmdreko/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.5/src/routing/method_routing.rs:385:1
    |
385 | top_level_handler_fn!(get, GET);
    | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `get`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `fn(axum::http::Request<Body>, String) -> impl Future<Output = &'static str> {foo_d}: Handler<_, _>` is not satisfied
   --> src/main.rs:8:26
    |
8   |         .route("/d", get(foo_d))
    |                      --- ^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(axum::http::Request<Body>, String) -> impl Future<Output = &'static str> {foo_d}`
    |                      |
    |                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `axum::routing::get`
   --> /home/kmdreko/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.5/src/routing/method_routing.rs:385:1
    |
385 | top_level_handler_fn!(get, GET);
    | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `get`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `fn() -> impl Future<Output = &'static str> {foo_e}: Handler<_, _>` is not satisfied
   --> src/main.rs:9:26
    |
9   |         .route("/e", get(foo_e))
    |                      --- ^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn() -> impl Future<Output = &'static str> {foo_e}`
    |                      |
    |                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `axum::routing::get`
   --> /home/kmdreko/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.5/src/routing/method_routing.rs:385:1
    |
385 | top_level_handler_fn!(get, GET);
    | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `get`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `fn(String, HeaderMap) -> impl Future<Output = &'static str> {foo_f}: Handler<_, _>` is not satisfied
   --> src/main.rs:10:26
    |
10  |         .route("/f", get(foo_f))
    |                      --- ^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(String, HeaderMap) -> impl Future<Output = &'static str> {foo_f}`
    |                      |
    |                      required by a bound introduced by this call
    |
    = help: the following other types implement trait `Handler<T, S>`:
              <Layered<L, H, T, S> as Handler<T, S>>
              <MethodRouter<S> as Handler<(), S>>
note: required by a bound in `axum::routing::get`
   --> /home/kmdreko/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.5/src/routing/method_routing.rs:385:1
    |
385 | top_level_handler_fn!(get, GET);
    | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^
    | |                     |
    | |                     required by a bound in this function
    | required by this bound in `get`
    = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)

What are the rules for implementing handler functions? How can I find out why they are failing? Why aren't these errors more helpful?

This is meant as a canonical target for common axum handler errors.


Solution

  • TL;DR: The rules are below but #[debug_handler] can get you on your way quickly.


    The best resources are spread between the axum::handler and axum::extract modules. The former has a section that enumerates handlers:

    • Are async fns.
    • Take no more than 16 arguments that all implement Send.
    • All except the last argument implement FromRequestParts.
    • The last argument implements FromRequest.
    • Returns something that implements IntoResponse.
    • If a closure is used it must implement Clone + Send and be 'static.
    • Returns a future that is Send. The most common way to accidentally make a future !Send is to hold a !Send type across an await.

    Examples are always good so lets look at each function to see why they don't work:

    • async fn foo_a(_: MyExtractor) -> &'static str {
          "hello world!"
      }
      

      This does not work since there is not a FromRequestParts or FromRequest implementation for MyExtractor.

    • async fn foo_b() -> MyResponse {
          MyResponse
      }
      

      This does not work since the return type does not implement IntoResponse.

    • async fn foo_c(body: Json<MyBody>) -> Json<MyBody> {
          body
      }
      

      This one is trickier because axum's Json type does implement both FromRequest and IntoResponse, but it still fails because additional constraints were not met. This can affect a number of extractor types:

      • T must implement DeserializeOwned for Json<T> to implement FromRequest
      • T must implement Serialize for Json<T> to implement IntoResponse
      • T must be Clone for Extension<T> to implement FromRequestParts
      • T must implement DeserializeOwned for Path<T> to implement FromRequestParts
      • T must implement DeserializeOwned for Query<T> to implement FromRequestParts
      • many others
    • async fn foo_d(_req: Request, _body: String) -> &'static str {
          "yum food"
      }
      

      This one does not work because both Request and String implement FromRequest when only one of them is allowed. Otherwise both will attempt to consume the request body.

    • async fn foo_e() -> &'static str {
          static LIST: std::sync::Mutex<Vec<i32>> = std::sync::Mutex::new(Vec::new());
      
          let _list = LIST.lock().unwrap();
          let _ = foo_b().await;
          drop(_list);
      
          "checked it twice"
      }
      

      This one does not compile since the Future being returned is !Send. This can happen when a !Send type is used across an .await point.

      • A Mutex guard from the standard library does not implement Send. Use parking-lot or an async mutex.
      • An Rc does not implement Send and can be a common culprit.
      • many others
    • async fn foo_f(_body: String, _headers: HeaderMap) -> &'static str {
          "foofy"
      }
      

      This one only has one extractor that consumes the body, but it must go at the end. Here the HeaderMap extractor needs to be listed first.

    • not mentioned but there's a whole concept of State that can propagate through routers and into handlers where a mismatch can cause the same error.


    However, even if you know these rules, it may not be clear which one is in error. An extractor may have yet another constraint that you don't know is missing. But the error message doesn't give you any indication which part is wrong, so you could end up wasting type digging into a response problem, when ultimately you accidentally introduced a !Send type or something.

    Is there a better option? Yes, axum provides a #[debug_handler] macro that you can annotate your failing handler functions with which will make it generate better errors. Though be sure to enable the "macros" feature:

    axum = { version = "...", features = ["macros"] }
    
    #[axum::debug_handler]
    async fn foo_a(_: MyExtractor) -> &'static str {
        "hello world!"
    }
    

    Here is what the errors above look like when all handlers are annotated with #[debug_handler]:

    error: Can't have two extractors that consume the request body. `Request<_>` and `String` both do that.
      --> src/main.rs:33:16
       |
    33 | async fn foo_d(_req: Request, _body: String) -> &'static str {
       |                ^^^^
    
    error: `String` consumes the request body and thus must be the last argument to the handler function
      --> src/main.rs:49:23
       |
    49 | async fn foo_f(_body: String, _headers: HeaderMap) -> &'static str {
       |                       ^^^^^^
    
    error[E0277]: the trait bound `for<'de> MyBody: serde::de::Deserialize<'de>` is not satisfied
      --> src/main.rs:28:22
       |
    28 | async fn foo_c(body: Json<MyBody>) -> Json<MyBody> {
       |                      ^^^^ the trait `for<'de> serde::de::Deserialize<'de>` is not implemented for `MyBody`
       |
       = help: the following other types implement trait `serde::de::Deserialize<'de>`:
                 bool
                 char
                 isize
                 i8
                 i16
                 i32
                 i64
                 i128
               and 144 others
       = note: required for `MyBody` to implement `serde::de::DeserializeOwned`
       = note: required for `Json<MyBody>` to implement `FromRequest<()>`
       = help: see issue #48214
    
    error[E0277]: the trait bound `MyResponse: IntoResponse` is not satisfied
      --> src/main.rs:23:21
       |
    23 | async fn foo_b() -> MyResponse {
       |                     ^^^^^^^^^^ the trait `IntoResponse` is not implemented for `MyResponse`
       |
       = help: the following other types implement trait `IntoResponse`:
                 Box<str>
                 Box<[u8]>
                 axum::body::Bytes
                 Body
                 axum::extract::rejection::FailedToBufferBody
                 axum::extract::rejection::LengthLimitError
                 axum::extract::rejection::UnknownBodyError
                 axum::extract::rejection::InvalidUtf8
               and 121 others
    note: required by a bound in `__axum_macros_check_foo_b_into_response::{closure#0}::check`
      --> src/main.rs:23:21
       |
    23 | async fn foo_b() -> MyResponse {
       |                     ^^^^^^^^^^ required by this bound in `check`
    
    error[E0277]: the trait bound `MyExtractor: FromRequestParts<()>` is not satisfied
      --> src/main.rs:18:19
       |
    18 | async fn foo_a(_: MyExtractor) -> &'static str {
       |                   ^^^^^^^^^^^ the trait `FromRequestParts<()>` is not implemented for `MyExtractor`
       |
       = help: the following other types implement trait `FromRequestParts<S>`:
                 <HeaderMap as FromRequestParts<S>>
                 <Extension<T> as FromRequestParts<S>>
                 <Method as FromRequestParts<S>>
                 <axum::http::request::Parts as FromRequestParts<S>>
                 <Uri as FromRequestParts<S>>
                 <Version as FromRequestParts<S>>
                 <ConnectInfo<T> as FromRequestParts<S>>
                 <Extensions as FromRequestParts<S>>
               and 28 others
       = note: required for `MyExtractor` to implement `FromRequest<(), axum_core::extract::private::ViaParts>`
    note: required by a bound in `__axum_macros_check_foo_a_0_from_request_check`
      --> src/main.rs:18:19
       |
    18 | async fn foo_a(_: MyExtractor) -> &'static str {
       |                   ^^^^^^^^^^^ required by this bound in `__axum_macros_check_foo_a_0_from_request_check`
    
    error: future cannot be sent between threads safely
      --> src/main.rs:37:1
       |
    37 | #[axum::debug_handler]
       | ^^^^^^^^^^^^^^^^^^^^^^ future returned by `foo_e` is not `Send`
       |
       = help: within `impl Future<Output = &'static str>`, the trait `Send` is not implemented for `MutexGuard<'_, Vec<i32>>`
    note: future is not `Send` as this value is used across an await
      --> src/main.rs:42:21
       |
    41 |     let _list = LIST.lock().unwrap();
       |         ----- has type `MutexGuard<'_, Vec<i32>>` which is not `Send`
    42 |     let _ = foo_b().await;
       |                     ^^^^^ await occurs here, with `_list` maybe used later
    note: required by a bound in `__axum_macros_check_foo_e_future::check`
      --> src/main.rs:37:1
       |
    37 | #[axum::debug_handler]
       | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
       = note: this error originates in the attribute macro `axum::debug_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
    

    It may take multiple passes of fixing, and the original error may still be listed, but these error messages produced by the attribute give you a much better indication than without.

    Why aren't these errors more helpful?

    It has to do with the way that functions with differing numbers of parameters can be used to satisfy the same constraint. A naïve implementation would run into conflicts, so it requires some trickery. See the Q&A here for roughly how it is done. But in the end, all that is asked to the compiler is "does this function satisfy Handler" and the only effective answer by the compiler is "yes" (and it compiles) or "no" (and you get a generic error).