GuardAPI Logo
GuardAPI
GuardAPI Logo GuardAPI

Fix Improper Error Handling in Actix Web

Improper error handling in Actix Web typically manifests as 'leaky' responses where internal system details—stack traces, database schema errors, or filesystem paths—are returned to the client. This provides an attacker with a blueprint of your infrastructure. To secure an Actix application, you must decouple internal failure states from the HTTP responses sent to the user.

The Vulnerable Pattern

use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use serde::Serialize;

#[derive(Serialize)] struct User { id: i32, name: String }

#[get(“/user/{id}”)] async fn get_user(id: web::Path) -> impl Responder { // VULNERABILITY: Directly returning internal database errors to the client // or using unwrap() which can cause the worker to crash/leak info. let user_result = some_db_call(id.into_inner()).await;

match user_result {
    Ok(user) => HttpResponse::Ok().json(user),
    Err(e) => HttpResponse::InternalServerError().body(format!("Database Error: {:?}", e)) 
    // ^-- LEAK: Exposes raw DB driver errors (e.g., SQL syntax, table names)
}

}

The Secure Implementation

The secure implementation utilizes the `actix_web::ResponseError` trait combined with the `thiserror` crate to create a robust error-handling layer. Instead of piping raw error strings to the `HttpResponse`, we define a custom enum that distinguishes between what the developer sees (via logging) and what the attacker sees (sanitized JSON). By returning a `Result`, Actix automatically invokes `error_response()` when an error occurs, ensuring no sensitive metadata escapes the execution context.

use actix_web::{get, web, HttpResponse, ResponseError, http::StatusCode};
use thiserror::Error;
use log::error;

#[derive(Error, Debug)] pub enum MyError { #[error(“Internal Server Error”)] DbError(#[from] sqlx::Error), #[error(“User not found”)] NotFound, }

// Securely map internal errors to sanitized HTTP responses impl ResponseError for MyError { fn error_response(&self) -> HttpResponse { match self { MyError::DbError(ref e) => { error!(“Database failure: {:?}”, e); // Log the real error for devs HttpResponse::InternalServerError().json(“A generic error occurred”) // Sanitize for users } MyError::NotFound => HttpResponse::NotFound().json(“Resource not found”), } }

fn status_code(&self) -> StatusCode {
    match *self {
        MyError::DbError(_) => StatusCode::INTERNAL_SERVER_ERROR,
        MyError::NotFound => StatusCode::NOT_FOUND,
    }
}

}

#[get(“/user/{id}”)] async fn get_user(id: web::Path) -> Result<HttpResponse, MyError> { let user = some_db_call(id.into_inner()).await.map_err(MyError::DbError)?; Ok(HttpResponse::Ok().json(user)) }

Protect your Actix Web API

Don't rely on manual checks. GuardAPI's Gemini 3 Pro engine detects Improper Error Handling and logic flaws in seconds.

Run Automated Audit

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.