Course contentsShow
← Rust
Lesson 870 of 1,9107. Error Handling PatternsFree lesson

Sanitizing Errors at Public APIs

Strip sensitive internal details from errors before exposing them to consumers.

In this lesson, you’ll learn how to shield your system's internal architecture by stripping sensitive information from errors before they cross the boundary of your public-facing API.

The Information Leak Problem

When you build a library or a service, your internal errors often contain highly specific details—database connection strings, file paths, or private business logic identifiers. While these details are invaluable for debugging, exposing them to a public API consumer creates a security risk and leaks implementation details that you might want to change later.

If a database query fails, your internal error might look like DatabaseError("failed to connect to 10.0.0.5:5432 with user 'admin'"). If you propagate this directly, your consumer now knows your internal infrastructure topology.

Sanitizing at the Boundary

To sanitize errors, you must transform your rich, internal error types into opaque, public-facing ones as they exit your crate's boundary. A common pattern is to define a "Public Error" enum and map internal errors into it using map_err.

Consider this transformation:

pub enum PublicError {
    InternalFailure,
    InvalidInput,
}

// Internal function with rich context
fn fetch_user_data(id: u32) -> Result<Data, InternalError> {
    // ... might return an error containing sensitive paths or SQL logs
}

// Public-facing wrapper
pub fn get_user(id: u32) -> Result<Data, PublicError> {
    fetch_user_data(id).map_err(|err| {
        // Log the full detail internally for your eyes only
        log::error!("Internal diagnostic: {:?}", err);
        
        // Return a generic, safe variant to the user
        PublicError::InternalFailure
    })
}

By mapping the error, you maintain full observability through logging while providing a consistent, minimal interface to your users.

Best Practices for Sanitization

  1. Never pass the source error through: If you use anyhow or a similar crate, be careful not to include the internal error in your display implementation if that display implementation is ever serialized to a public API response.
  2. Log the unique ID: When you sanitize an error, log the full internal details along with a "Correlation ID." You can include this ID in the public error so the user can report it to you, allowing you to find the sensitive details in your private logs without ever exposing them to the user.

Key Takeaway: Always decouple your internal error diagnostics from your public API surface by explicitly mapping internal failures to sanitized, domain-specific error variants.