Debug compiler errors in Axum handlers
I was adding tokio-postgres
to a project that previously used Sqlite when I got the following error:
error[E0277]: the trait bound `fn(State<Arc<AppState>>, Json<CreateShortUrl>) -> impl Future<Output = impl IntoResponse> {create_short_url}: Handler<_, _>` is not satisfied
--> src/main.rs:39:42
|
39 | .route("/create-short-url", post(create_short_url))
| ---- ^^^^^^^^^^^^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(State<Arc<AppState>>, Json<...>) -> ... {create_short_url}`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Handler<T, S>`:
`Layered<L, H, T, S>` implements `Handler<T, S>`
`MethodRouter<S>` implements `Handler<(), S>`
note: required by a bound in `post`
--> /Users/markuswendorf/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.7.9/src/routing/method_routing.rs:443:1
|
443 | top_level_handler_fn!(post, POST);
| ^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^
| | |
| | required by a bound in this function
| required by this bound in `post`
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
I didn’t really understand what was wrong with my code: this error originates in the macro 'top_level_handler_fn'
.
To get better errors from handler implementations you can use the #[axum::debug_handler]
attribute.
Make sure the macros
feature is enabled for Axum:
axum = { version = "0.7.9", features = ["macros"] }
Adding the attribute to my handler reveals the underlying issue:
#[axum::debug_handler]
async fn create_short_url(
State(state): State<Arc<AppState>>,
Json(payload): Json<CreateShortUrl>,
) -> impl IntoResponse
The error now reads:
future cannot be sent between threads safely
within `impl Future<Output = impl IntoResponse>`, the trait
`Send` is not implemented for `std::sync::MutexGuard<'_, PostgresStorage>`
Which prompted me to replace the std::sync::Mutex
with tokio::sync::Mutex
. And voilà the issue is gone.
The tokio::sync::Mutex
works here because the tokio::sync::MutexGuard
can be held across any .await
point as it is Send
.