Today I Learned: Trait Objects for Error Handling

C…
crusty.rustacean
Published on November 09, 2025 • Updated November 10, 2025

A short lesson in using a trait object to ease error handling

notes
trait-objects rust error-handling traits
0 likes

I’m fiddling about with the Rama framework. There’s a hello-world style example in the GitHub repo that I took as a base, adapting it to play around and learn.

Here’s what I came up with:

// src/main.rs

// dependencies
use anyhow::{Context, Result};
use rama::{http::StatusCode, http::server::HttpServer, rt::Executor, service::service_fn};
use std::convert::Infallible;

// handler which returns a 200 OK status code and empty body
async fn health_check() -> Result<StatusCode, Infallible> {
    Ok(StatusCode::OK)
}

#[tokio::main]
async fn main() -> Result<()> {
    let exec = Executor::default();
    HttpServer::auto(exec)
        .listen("127.0.0.1:8080", service_fn(health_check))
        .await
        .map_err(|e| anyhow::anyhow!("{}", e))
        .context("Failed to start HTTP server on 127.0.0.1:8080")?;

    Ok(())
}

I’ll use this example in a variety of ways going forward, because it illustrates several things. For now, let’s look at the error handling.

In the repo example, the authors simply .unwrap() after the .await to avoid showing the specifics of error handling. This is fine, but I always like to push a little to see if I can work the error handling out.

The await call will eventually resolve into a Result<(), Box<dyn Error + Send + Sync + 'static> where the error is a heap-allocated trait object. This approach adds flexibility. It’s basically saying that the error type can be anything that:

  • implements the Error trait
  • is safe to send across threads
  • is safe to be mutated across threads
  • will always have ownership of itself

The end part of the code above leverages .map_err() which takes our trait object and converts it into an anyhow error, to which we add some extra context and explanation.

There is a small runtime penalty for using trait objects, given they use heap memory, so you have to evaluate that in the context of whatever it is your doing. It might be acceptable.

Trait objects are a great way to enable flexibility in your code and are a great addition to the toolbox.

C…
crusty.rustacean

Comments

Loading comments...