Error
The std::error::Error trait (also available in core::error::Error since Rust 1.81) is the standard interface for error values, combining human-readable formatting (Display), developer diagnostics (Debug), and causal error chaining (source).
Trait Definition
pub trait Error: Debug + Display {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
Because Error has Debug and Display as supertraits:
- Every
Errortype must implementDebug(typically via#[derive(Debug)]) andDisplay. - If the error does not wrap a lower-level cause, the
impl Error for MyError {}block can be completely empty becausesource()defaults toNone.
Implementing Error with Causal Chaining (source)
Overriding source(&self) exposes the underlying lower-level error (&(dyn Error + 'static)) so error reporters and logging frameworks can walk the entire causal chain:
use std::error::Error;
use std::fmt;
use std::num::ParseIntError;
#[derive(Debug)]
struct ConfigError {
key: &'static str,
cause: ParseIntError,
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid integer for configuration key '{}'", self.key)
}
}
impl Error for ConfigError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.cause)
}
}
fn parse_port(raw: &str) -> Result<u16, ConfigError> {
raw.parse::<u16>().map_err(|err| ConfigError {
key: "PORT",
cause: err,
})
}
fn main() {
let err = parse_port("not_a_number").unwrap_err();
println!("Top-level error: {err}");
let mut current: Option<&dyn Error> = err.source();
while let Some(cause) = current {
println!(" Caused by: {cause}");
current = cause.source();
}
}
Top-level error: invalid integer for configuration key 'PORT'
Caused by: invalid digit found in string
Type-Erased Errors with Box<dyn Error>
The standard library provides a blanket conversion impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a>. Functions that can fail with several different error types (such as main(), CLI scripts, or test harnesses) can return Result<T, Box<dyn Error>> and use the ? operator on any error type that implements std::error::Error:
use std::error::Error;
fn parse_and_access(items: &[&str], index_str: &str) -> Result<i32, Box<dyn Error>> {
let idx: usize = index_str.parse()?; // Converts ParseIntError -> Box<dyn Error>
let raw = items.get(idx).ok_or("index out of bounds")?; // Converts &str -> Box<dyn Error>
let val: i32 = raw.parse()?;
Ok(val)
}
fn main() {
let data = ["10", "25", "bad"];
println!("Valid: {:?}", parse_and_access(&data, "1"));
println!("Missing: {:?}", parse_and_access(&data, "9"));
}
Valid: Ok(25)
Missing: Err("index out of bounds")