Trait binding error with axum

I'm working on a backend server that I'm planning on using to serve up CRUD endpoints, and I'm running into an error I'm just too much of a newbie in Rust to identify the root cause of an issue my IDE is flagging:

the trait bound `{closure@src/server/router.rs:206:17: 213:24}: Handler<_, _>` is not satisfied
Consider using `#[axum::debug_handler]` to improve the error messagerustc[Click for full compiler diagnostic](rust-analyzer-diagnostics-view:/diagnostic%20message%20[0]?0#file:///home/damon/Development/main-serve/src/server/router.rs)

router.rs(254, 36): required by a bound introduced by this call

method_routing.rs(167, 16): required by a bound in `axum::routing::get`

Obviously I'm using axum for this. Here's the pertinent code:

EndpointAction::Crud => {
    let ep = ep.clone();
    let path_owned = path.to_string();
    let handler = move |state: State<AppState>,
                        remote_addr: Option<Extension<SocketAddr>>,
                        method: axum::http::Method,
                        body: Option<axum::Json<serde_json::Value>>,
                        path_params: Option<Path<HashMap<String, String>>>,
                        query: Option<Query<HashMap<String, String>>>,
                        headers: HeaderMap| {
        let ep = ep.clone();
        let path = path_owned.clone();
        async move {
            let query_map = query.map(|q| q.0).unwrap_or_default();
            let state_clone = state.clone();
            let auth_info = run_pre_checks(
                state_clone,
                &headers,
                &query_map,
                &ep,
                extract_addr(remote_addr),
            )
            .await?;
            let context = crate::context::RequestContext {
                user_id: auth_info.subject.clone().into(),
                user_role: auth_info.role,
                headers: headers
                    .iter()
                    .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
                    .collect(),
                method: method.to_string(),
                path,
                query_params: query_map.clone(),
            };
            let response = handle_crud(
                state,
                method,
                path_params,
                Query(query_map),
                body,
                ep,
                context,
            )
            .await?;
            Ok::<Response, AppError>(response.into_response())
        }
    };
    let method_router = match method {
        HttpMethod::Get => axum::routing::get(handler),
        HttpMethod::Post => axum::routing::post(handler),
        HttpMethod::Put => axum::routing::put(handler),
        HttpMethod::Patch => axum::routing::patch(handler),
        HttpMethod::Delete => axum::routing::delete(handler),
        HttpMethod::Head => axum::routing::head(handler),
        HttpMethod::Options => axum::routing::options(handler),
    };

    if let Some(cors_config) = cors {
        app = app
            .route(path, method_router)
            .layer(build_cors_layer(cors_config));
    } else {
        app = app.route(path, method_router);
    }
}

The result is a handler that looks like this:

let handler: impl Fn(State<AppState>, Option<Extension<SocketAddr>>, Method, Option<Json<Value>>, Option<Path<HashMap<String, String>>>, Option<Query<HashMap<String, String>>>, HeaderMap) -> impl Future<Output = Result<Response<Body>, AppError>>

Like I said, I'm too much of a newbie, because this looks (to me) like what axum expects. And - being honest here - I lifted most of this from other backend server projects I've seen that use a very similar pattern.

I don't want to use AI to answer this or fix the error, because I'm trying to learn Rust for myself, but I'm stumped. I'm certain that I'm missing something incredibly simple, like ordering in move or something, but I could sure use some guidance.

Annotate your handler with #[axum::debug_handler] to improve the error message, as it changes the desugaring to give rustc a better chance at giving you context when errors happen (but Axum doesn't do it by default because it makes compiles slower).

Also, if you click "Click for full compiler diagnostic" the diagnostic might be easier to read, as it has the code context for each thing it points at.

This is a guess at what the problem might be, since you haven't provided us with enough information about the custom types you're using, but in order for a function to implement Handler, it must return Future<Output=Res> where Res: IntoResponse, but your Output is Result<Response<Body>, AppError>, which will only implement IntoResponse if AppError implements IntoResponse. Does it implement that?

It does NOT! I think you've found it! Thank you so much!