Lesson 15 / 25

Custom Error Types

Enums that describe what went wrong.

Display, Error and From

For applications and libraries, define an error enum listing the failure cases, implement Display (human message) and std::error::Error, and implement From<OtherError> so ? converts underlying errors automatically. Crates such as thiserror (for libraries) generate this boilerplate, and anyhow (for applications) offers a convenient catch-all error type with context.

An OrderError enum with automatic conversion, run

I ran this with Rust 1.99.0 (cargo run, edition 2024, standard library only). A valid order succeeds; "two" fails to parse and ? converts the ParseIntError into OrderError::InvalidQty through From; the lamp returns OutOfStock. Display produces readable messages.

use std::fmt;

#[derive(Debug)]
enum OrderError {
    OutOfStock(String),
    InvalidQty(std::num::ParseIntError),
}

impl fmt::Display for OrderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            OrderError::OutOfStock(item) => write!(f, "{item} is out of stock"),
            OrderError::InvalidQty(e) => write!(f, "invalid quantity: {e}"),
        }
    }
}

impl std::error::Error for OrderError {}

impl From<std::num::ParseIntError> for OrderError { // lets ? convert automatically
    fn from(e: std::num::ParseIntError) -> Self { OrderError::InvalidQty(e) }
}

fn order(item: &str, qty: &str) -> Result<String, OrderError> {
    let n: u32 = qty.parse()?;
    if item == "lamp" {
        return Err(OrderError::OutOfStock(item.to_string()));
    }
    Ok(format!("ordered {n} x {item}"))
}

fn main() {
    for (item, qty) in [("pen", "2"), ("pen", "two"), ("lamp", "1")] {
        match order(item, qty) {
            Ok(msg) => println!("{msg}"),
            Err(e) => println!("error: {e}"),
        }
    }
}

Output:

ordered 2 x pen
error: invalid quantity: invalid digit found in string
error: lamp is out of stock

thiserror for libraries, anyhow for apps

Libraries expose precise error enums; applications often just need context-rich errors to log.

Quick check: Why implement From<ParseIntError> for your error type?

  • So ? can convert a ParseIntError into your error automatically
  • To print errors in colour
  • To make errors Copy
  • Because Display requires it
Answer

So ? can convert a ParseIntError into your error automatically — Conversion powers the ? operator.