tokio-rs/axum

Cannot work with tower-http's RequestDecompressionLayer

Closed this issue · 3 comments

Bug Report

Version

│   │   │   │   │   │   │       ├── axum v0.6.20
│   │   │   │   │   │   │       │   ├── axum-core v0.3.4
│   │   │   │   │   │   │   │       ├── axum v0.6.20 (*)
│       │   │   │   │   │   │   │   │   │   │   ├── axum v0.6.20
│       │   │   │   │   │   │   │   │   │   │   │   ├── axum-core v0.3.4 (*)
│       │   │   │   │   │   │   │   │   │   ├── axum v0.6.20 (*)
│       │   │   │   │   │   │   │   │   │   ├── axum-macros v0.3.8 (proc-macro)
│       │   │   │   │   │   │   │   │   │   ├── axum-test-helper v0.3.0
│       │   │   │   │   │   │   │   │   │   │   ├── axum v0.6.20 (*)
├── axum v0.6.20 (*)
├── axum-test-helper v0.3.0 (*)

Platform

Darwin tisondeMacBook-Pro.local 22.5.0 Darwin Kernel Version 22.5.0: Mon Apr 24 20:53:19 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6020 arm64

Crates

Description

        Router::new()
            .route("/write", routing::post(influxdb_write_v1))
            .route("/api/v2/write", routing::post(influxdb_write_v2))
            .layer(RequestDecompressionLayer::new())
            .route("/ping", routing::get(influxdb_ping))
            .route("/health", routing::get(influxdb_health))
            .with_state(influxdb_handler)

throws

   Compiling servers v0.7.0 (/Users/tison/GreptimeWorkspace/greptimedb/src/servers)
error[E0277]: the trait bound `Infallible: std::convert::From<Box<(dyn StdError + std::marker::Send + std::marker::Sync + 'static)>>` is not satisfied
   --> src/servers/src/http.rs:702:20
    |
702 |             .layer(RequestDecompressionLayer::new().gzip(true))
    |              ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<Box<(dyn StdError + std::marker::Send + std::marker::Sync + 'static)>>` is not implemented for `Infallible`
    |              |
    |              required by a bound introduced by this call
    |
    = help: the trait `std::convert::From<!>` is implemented for `Infallible`
    = help: for that trait implementation, expected `!`, found `Box<(dyn StdError + std::marker::Send + std::marker::Sync + 'static)>`
    = note: required for `Box<(dyn StdError + std::marker::Send + std::marker::Sync + 'static)>` to implement `Into<Infallible>`
note: required by a bound in `AxumRouter::<S, B>::layer`
   --> /Users/tison/.cargo/registry/src/index.crates.io-6f17d22bba15001f/axum-0.6.20/src/routing/mod.rs:238:62
    |
233 |     pub fn layer<L, NewReqBody>(self, layer: L) -> Router<S, NewReqBody>
    |            ----- required by a bound in this associated function
...
238 |         <L::Service as Service<Request<NewReqBody>>>::Error: Into<Infallible> + 'static,
    |                                                              ^^^^^^^^^^^^^^^^ required by this bound in `Router::<S, B>::layer`

For more information about this error, try `rustc --explain E0277`.

But the TimeoutLayer in tower has the same:

impl<S> Layer<S> for TimeoutLayer {
    type Service = Timeout<S>;

    fn layer(&self, service: S) -> Self::Service {
        Timeout::new(service, self.timeout)
    }
}

impl<S, Request> Service<Request> for Timeout<S>
where
    S: Service<Request>,
    S::Error: Into<crate::BoxError>,
{
    type Response = S::Response;
    type Error = crate::BoxError;
    type Future = ResponseFuture<S::Future>;
    ....
}

pub type BoxError = Box<dyn std::error::Error + Send + Sync>;

why this one gets compiled?

Work around with:

            .layer(
                ServiceBuilder::new()
                    .layer(HandleErrorLayer::new(handle_error))
                    .layer(RequestDecompressionLayer::new()),
            )

where

async fn handle_error(err: BoxError) -> Json<HttpResponse> {
    error!(err; "Unhandled internal error");
    Json(HttpResponse::Error(...))
}

HandleErrorLayer is the correct solution. See the documentation for more details.

With regards to TimeoutLayer, I suspect you are mixing up tower's TimeoutLayer which does raise service-level errors, with tower-https TimeoutLayer which doesn't.

Next time if you have a problem like this and it's not clear whether it's a bug in axum, please use the Q&A section. Thanks!