🌞

Axum: the trait `Handler<_, ()>` is not implemented for fn item

While playing around with Axum, I ran into the above-mentioned compile-time error. The underlying issue, in my case, was holding a type that’s not Send across an await. Read on if you’re interested in the details.

The full error message I was given was the following:

              .fallback(fallback_handler);
    |          -------- ^^^^^^^^^^^^^^^^ the trait `Handler<_, ()>` is not implemented for fn item `fn(Extension<State>, Request<Body>) -> impl Future<Output = impl IntoResponse> {fallback_handler}`
	|          |
	|          required by a bound introduced by this call
    |
    = help: the trait `Handler<T, S, B2>` is implemented for `Layered<L, H, T, S, B, B2>`

The error message didn’t help me in figuring out what’s going on. The most confusing part was that the problem seemed to be caused by instantiating a struct I had just written, but I hadn’t changed anything about the function signature or the return value.

My handler looked something like this:

async fn fallback_handler(
    Extension(state): Extension<State>,
    request: Request<Body>,
) -> impl IntoResponse {
	let mut errors: Vec<Box<dyn Error>> = vec![];
	// [...]
	let tera = state.tera.lock().await;
	// [...]
	StatusCode::OK
}

Now, if you’re familiar with async Rust, you might already see the problem. It’s the same issue described in detail here, namely that

  1. std::error::Error is not Send, i.e. it cannot safely be sent between threads
  2. Holding a non-Send type across an await results in a non-Send Future (explanation)

Axum’s Handler type, however, requires the resulting Future to be Send, as can be seen here:

pub trait Handler<T, S, B = Body>: Clone + Send + Sized + 'static {
	/// The type of future calling this handler returns.
	type Future: Future<Output = Response> + Send + 'static;
	// [...]
}

So, long story short: don’t try to hold non-Send types across await calls when you’re writing an Axum handler.