Actix-Web: Using a custom error handler to alter the response body

I'm referring to: ErrorHandlers in actix_web 2.0.0

I'm trying to implement one that can set a new body.

This is the relevant part of my main.rs:

 App::new()
    .wrap(ErrorHandlers::new().handler(
        actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
        render_500,
    ))

Here are various implementations of render_500 that all result in different compiler errors:

Implementation A:

pub fn render_500(
    mut res: dev::ServiceResponse<Body>,
) -> actix_web::Result<ErrorHandlerResponse<Body>> {
    let req = res.request();
    let res = res.map_body(|_, _| ResponseBody::Body(Body::from("test")));
    Ok(ErrorHandlerResponse::Response(res))
}

Results in Error A:

Error A
error[E0271]: type mismatch resolving `<<impl actix_service::ServiceFactory as actix_service::ServiceFactory>::Service as actix_web::dev::Service>::Response == actix_web::dev::ServiceResponse`
  --> src/main.rs:97:14
   |
97 |             .wrap(ErrorHandlers::new().handler(
   |              ^^^^ expected struct `actix_web::middleware::logger::StreamLog`, found enum `actix_web::dev::Body`
   |
   = note: expected struct `actix_web::dev::ServiceResponse<actix_web::middleware::logger::StreamLog<actix_web::dev::Body>>`
              found struct `actix_web::dev::ServiceResponse<actix_web::dev::Body>`
   = note: required because of the requirements on the impl of `actix_web::dev::Transform<<impl actix_service::ServiceFactory as actix_service::ServiceFactory>::Service>` for `actix_web::middleware::errhandlers::ErrorHandlers<actix_web::dev::Body>`

error: aborting due to previous error

Implementation B:

pub fn render_500<B>(
    mut res: dev::ServiceResponse<B>,
) -> actix_web::Result<ErrorHandlerResponse<B>> {
    let req = res.request();
    let res = res.map_body(|_, _| ResponseBody::Body(Body::from("test")));
    Ok(ErrorHandlerResponse::Response(res))
}

Results in Error B:

Error B
error[E0308]: mismatched types
  --> src/errors.rs:94:39
   |
80 | pub fn render_500<B>(
   |                   - this type parameter
...
94 |     Ok(ErrorHandlerResponse::Response(res))
   |                                       ^^^ expected type parameter `B`, found enum `actix_web::dev::Body`
   |
   = note: expected struct `actix_web::dev::ServiceResponse<B>`
              found struct `actix_web::dev::ServiceResponse<actix_web::dev::Body>`
   = help: type parameters must be constrained to match other types
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

error: aborting due to previous error

I don't quiet understand Error A in the first place, since in the source B clearly is implementing Body and wrap is using ServiceResponse<B1> where B1 is defined as MessageBody which is also implemented by Body, which is why I thought this should work.
The same logic basically applies to Implementation B.

Can anyone give me a hint or some advice to which approach would be the right one?

1 Like

Hi!
I'm just begin with Rust and Actix and have faced with the same problem and into_body helps in my case.

pub fn render_500<B>(
    mut res: dev::ServiceResponse<B>,
) -> actix_web::Result<ErrorHandlerResponse<B>> {
    let req = res.request();
    let res = res.map_body(|_, _| ResponseBody::Body(Body::from("test")).into_body());
    Ok(ErrorHandlerResponse::Response(res))
}