Skip to main content

Error Handling

Gracefully returning errors to clients.

Actix 4.9+ 6 min read

# Error Handling

In Rust, errors are handled via the Result type. Actix Web embraces this heavily. If a handler returns a Result<T, E>, and E implements Actix Web's ResponseError trait, Actix will automatically convert the error into an HTTP response if the result is Err.

##The ResponseError Trait

The actix_web::error::ResponseError trait allows you to define how an error type maps to an HTTP status code and a response body.

code_blocksrust
use actix_web::{error::ResponseError, http::StatusCode, HttpResponse};
use std::fmt;

#[derive(Debug)]
enum UserError {
    NotFound,
    ValidationError(String),
}

impl fmt::Display for UserError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UserError::NotFound => write!(f, "User not found"),
            UserError::ValidationError(msg) => write!(f, "Validation error: {}", msg),
        }
    }
}

// Implement ResponseError for our custom enum
impl ResponseError for UserError {
    fn status_code(&self) -> StatusCode {
        match *self {
            UserError::NotFound => StatusCode::NOT_FOUND,
            UserError::ValidationError(_) => StatusCode::BAD_REQUEST,
        }
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::build(self.status_code())
            .body(self.to_string())
    }
}

##Using Errors in Handlers

Once your error implements ResponseError, you can just return it from your handler using the ? operator.

code_blocksrust
use actix_web::{web, Responder, Result};

async fn get_user(id: web::Path<u32>) -> Result<impl Responder, UserError> {
    if id.into_inner() == 0 {
        return Err(UserError::NotFound);
    }
    Ok("Found user!")
}

This pattern is incredibly powerful. It allows you to bubble up errors from your database layer or business logic layer directly into HTTP responses without writing repetitive match blocks in every handler. You can use libraries like thiserror to generate the Display and Error trait implementations easily, streamlining the process even further.

Was this page helpful?

Reference Implementation

The following code snippet demonstrates the authoritative pattern for this documentation.

src/main.rs
1use actix_web::{error, get, http::StatusCode, App, HttpResponse, HttpServer, Result};
2use derive_more::{Display, Error};
3
4#[derive(Debug, Display, Error)]
5#[display(fmt = "my error: {}", name)]
6struct MyError {
7 name: &'static str,
8}
9
10impl error::ResponseError for MyError {
11 fn status_code(&self) -> StatusCode {
12 StatusCode::BAD_REQUEST
13 }
14}
15
16#[get("/fail")]
17async fn fail() -> Result<&'static str, MyError> {
18 Err(MyError { name: "boom" })
19}
20
21#[actix_web::main]
22async fn main() -> std::io::Result<()> {
23 HttpServer::new(|| App::new().service(fail))
24 .bind("127.0.0.1:8080")?
25 .run()
26 .await
27}
Was this page helpful?