Warp: the trait `warp::reply::Reply` is not implemented

Hi there,

I have an issue while using warp:

async fn customize_error(err: Rejection) -> Result<impl Reply, Infallible> {
    let code;
    let message;

    if let Some(server_error) = err.find::<error::ServerError>() {
        code = StatusCode::INTERNAL_SERVER_ERROR;
        message = server_error.msg.to_owned();
    } else {
        code = StatusCode::INTERNAL_SERVER_ERROR;
        message = "UNHANDLED_REJECTION".to_string();
    }
    Ok(warp::reply::with_status(message, code))
}

#[tokio::main]
async fn main() {
    let get_endpoint =
        warp::path("endpoint")
            .and(warp::query())
            .map(move |params: HashMap<String, String>| {
                get_endpoint_fn(&params)
                    .and_then(|response| Ok(response))
                    .or_else(|e| Err(warp::reject::custom(e.into())))
            });

    let get_routes = warp::get().and(get_endpoint).recover(customize_error);

    let post_login = warp::path("login")
        .and(warp::path::end())
        .and(warp::body::form())
        .map(|params: HashMap<String, String>| {
            post_login_fn(&params)
                .and_then(|response| Ok(response))
                .or_else(|e| Err(warp::reject::custom(e.into())))
        });

    let post_routes = warp::post().and(post_login).recover(customize_error);

    let routes = get_routes.or(post_routes);

    warp::serve(routes).run(([127, 0, 0, 1], 4321)).await;
}

// error.rs
#[derive(Debug, Clone, Error, Serialize, PartialEq)]
pub struct ServerError {
    #[serde(skip)]
    pub status: StatusCode,
    pub msg: String,
}

impl Reject for ServerError {}

impl Display for ServerError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{} ({})", self.msg, self.status)
    }
}

impl ServerError {
    pub fn new(status: StatusCode, msg: &str) -> Self {
        ServerError {
            status,
            msg: msg.to_owned(),
        }
    }
}

impl From<anyhow::Error> for ServerError {
    fn from(err: anyhow::Error) -> Self {
        let e = match err.downcast::<ServerError>() {
            Ok(e) => return e,
            Err(e) => e,
        };

        ServerError::new(
            StatusCode::INTERNAL_SERVER_ERROR,
            &format!("Unhandled error type: {:#?}", e),
        )
    }
}

this doesn't build:

error[E0271]: type mismatch resolving `<warp::filter::recover::Recover<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filter::map::Map<warp::filter::and::And<warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>, impl warp::filter::Filter+std::marker::Copy>, [closure@src\main.rs:55:18: 64:14 get_auth_cfg_no_cookie:_]>>, fn(warp::reject::Rejection) -> impl core::future::future::Future {customize_error}> as warp::filter::FilterBase>::Error == warp::reject::Rejection`
   --> src\main.rs:103:29
    |
103 |     let routes = get_routes.or(post_routes);
    |                             ^^ expected enum `std::convert::Infallible`, found struct `warp::reject::Rejection`

error[E0277]: the trait bound `std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>: warp::reply::Reply` is not satisfied
   --> src\main.rs:106:17
    |
106 |     warp::serve(routes)
    |                 ^^^^^^ the trait `warp::reply::Reply` is not implemented for `std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>`
    | 
   ::: C:\Users\geobe\.cargo\registry\src\github.com-1ecc6299db9ec823\warp-0.2.2\src\server.rs:25:17
    |
25  |     F::Extract: Reply,
    |                 ----- required by this bound in `warp::server::serve`
    |
    = help: the following implementations were found:
              <std::result::Result<T, http::error::Error> as warp::reply::Reply>        
    = note: required because of the requirements on the impl of `warp::reply::Reply` for `(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,)`
    = note: required because of the requirements on the impl of `warp::reply::Reply` for `warp::generic::Either<(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,), (impl warp::reply::Reply,)>`
    = note: required because of the requirements on the impl of `warp::reply::Reply` for `(warp::generic::Either<(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,), (impl warp::reply::Reply,)>,)`
    = note: required because of the requirements on the impl of `warp::reply::Reply` for `warp::generic::Either<(warp::generic::Either<(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,), (impl warp::reply::Reply,)>,), (warp::generic::Either<(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,), (impl warp::reply::Reply,)>,)>`
    = note: required because of the requirements on the impl of `warp::reply::Reply` for `(warp::generic::Either<(warp::generic::Either<(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,), (impl warp::reply::Reply,)>,), (warp::generic::Either<(std::result::Result<impl warp::reply::Reply, warp::reject::Rejection>,), (impl warp::reply::Reply,)>,)>,)`

the two *_fn function return anyhow::Result<impl Reply> and I have an impl From<anyhow::Error> for ServerError and impl Reject for ServerError

Thank you for any insight :slight_smile:

It sounds like you have some sort of error type mismatch.

Indeed, but I don't see why. I'm trying to follow the rejection.rs example and I think I'm doing the same thing on the error type, but I'm obviously wrong ^^'

I would try to fix this error first:

   --> src\main.rs:103:29
    |
103 |     let routes = get_routes.or(post_routes);
    |                             ^^ expected enum `std::convert::Infallible`, found struct `warp::reject::Rejection`

Even this one I don't get it: which part is expecting Infallible? routes or or?

EDIT: I added the big type error above the part you quoted:

error[E0271]: type mismatch resolving `<warp::filter::recover::Recover<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filter::map::Map<warp::filter::and::And<warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>, impl warp::filter::Filter+std::marker::Copy>, [closure@src\main.rs:55:18: 64:14 get_auth_cfg_no_cookie:_]>>, fn(warp::reject::Rejection) -> impl core::future::future::Future {customize_error}> as warp::filter::FilterBase>::Error == warp::reject::Rejection`

Ok, I've moved the 2 .recover(customize_error) from the get_route and the post_route to routes:

let routes = get_routes.or(post_routes).recover(customize_error);

and it fixes:

 --> src\main.rs:103:29
    |
103 |     let routes = get_routes.or(post_routes);
    |                             ^^ expected enum `std::convert::Infallible`, found struct `warp::reject::Rejection`

I still have:

error[E0277]: the trait bound `std::result::Result<std::result::Result<impl warp::reply::Reply, _>, std::result::Result<_, warp::reject::Rejection>>: warp::reply::Reply` is not satisfied
   --> src\main.rs:104:17
    |
104 |     warp::serve(routes)
    |                 ^^^^^^ the trait `warp::reply::Reply` is not implemented for `std::result::Result<std::result::Result<impl warp::reply::Reply, _>, std::result::Result<_, 
warp::reject::Rejection>>`

This works (changing map for and_then + async block):

#[tokio::main]
async fn main() -> Result<()> {
    let cfg = Arc::new(Config {});

    let (get_cfg, post_cfg) = (cfg.clone(), cfg.clone());

    let get_fct1 =
        warp::path("fct1")
            .and(warp::query())
            .and_then(move |params: HashMap<String, String>| {
                let cfg = get_cfg.clone();
                async move {
                    fct1(&cfg, params)
                        .and_then(|response| Ok(response))
                        .or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
                }
            });

    let post_fct1 = warp::path("fct1")
        .and(warp::path::end())
        .and(warp::body::form())
        .and_then(move |params: HashMap<String, String>| {
            let cfg = post_cfg.clone();
            async move {
                fct1(&cfg, params)
                    .and_then(|response| Ok(response))
                    .or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
            }
        });

    let get_routes = warp::get().and(get_fct1);
    let post_routes = warp::post().and(post_fct1);

    let routes = get_routes.or(post_routes).recover(customize_error);

    warp::serve(routes).run(([127, 0, 0, 1], 4321)).await;
    Ok(())
}

fn fct1(cfg: &Config, p: HashMap<String, String>) -> Result<impl Reply> {
    Ok(warp::reply())
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.