Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Rust Dictionary

  1. Home
  2. Rust Dictionary
  3. Custom Error Types / thiserror

Custom Error Types / thiserror

In Rust, you can define custom error types to represent application-specific errors in a type-safe way. The basic pattern is to define error variants using an enum and provide error messages by implementing the Display trait.

Syntax

use std::fmt;
use std::error::Error;

// Define a custom error type.
#[derive(Debug)]
enum AppError {
    NotFound(String),
    ParseError(String),
    IoError(std::io::Error),
}

// Implement the Display trait to define error messages.
impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AppError::NotFound(s) => write!(f, "Not found: {}", s),
            AppError::ParseError(s) => write!(f, "Parse error: {}", s),
            AppError::IoError(e) => write!(f, "I/O error: {}", e),
        }
    }
}

// Implement the Error trait (an empty implementation is fine).
impl Error for AppError {}

Error Design Patterns

PatternDescription
enum MyError { ... }Defines error kinds as enum variants.
impl Display for MyErrorDefines a user-facing error message (required).
impl Error for MyError {}Marks the type as an error trait implementor (empty body is fine).
impl From<io::Error> for MyErrorEnables automatic conversion from another error type (allows use of the ? operator).
Box<dyn Error>A trait object used when you need to return multiple different error types.
type Result<T> = std::result::Result<T, MyError>Defines a type alias for Result to omit the error type annotation.

Sample Code

use std::fmt;
use std::error::Error;
use std::num::ParseIntError;

#[derive(Debug)]
enum CalcError {
    DivisionByZero,
    Overflow,
    ParseError(ParseIntError),
}

impl fmt::Display for CalcError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            CalcError::DivisionByZero => write!(f, "Division by zero error"),
            CalcError::Overflow => write!(f, "Overflow occurred"),
            CalcError::ParseError(e) => write!(f, "Number parse error: {}", e),
        }
    }
}

impl Error for CalcError {}

// Automatically converts ParseIntError into CalcError (enables use of the ? operator).
impl From<ParseIntError> for CalcError {
    fn from(e: ParseIntError) -> Self {
        CalcError::ParseError(e)
    }
}

// Custom Result type alias.
type CalcResult<T> = Result<T, CalcError>;

fn divide(a: i32, b: i32) -> CalcResult<i32> {
    if b == 0 {
        Err(CalcError::DivisionByZero)
    } else {
        Ok(a / b)
    }
}

// The ? operator automatically converts ParseIntError into CalcError.
fn parse_and_divide(a: &str, b: &str) -> CalcResult<i32> {
    let a: i32 = a.parse()?;  // ParseIntError is converted to CalcError::ParseError.
    let b: i32 = b.parse()?;
    divide(a, b)
}

fn main() {
    // Normal calculation.
    match divide(10, 2) {
        Ok(result) => println!("10 / 2 = {}", result),
        Err(e) => println!("Error: {}", e),
    }

    // Division by zero.
    match divide(10, 0) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
    }

    // Calculation involving string parsing.
    let cases = vec![
        ("20", "4"),
        ("abc", "4"),
        ("20", "0"),
    ];

    for (a, b) in cases {
        match parse_and_divide(a, b) {
            Ok(result) => println!("{} / {} = {}", a, b, result),
            Err(e) => println!("{} / {} error: {} ({:?})", a, b, e, e),
        }
    }

    // A simpler version using Box<dyn Error> (can return multiple error types).
    fn flexible_error(fail: bool) -> Result<i32, Box<dyn Error>> {
        if fail {
            Err("simple error".into())
        } else {
            Ok(42)
        }
    }
    println!("{:?}", flexible_error(false));
    println!("{:?}", flexible_error(true));
}

Notes

If you implement From<OtherError> on your custom error type, the ? operator will automatically convert errors for you. This lets you write clean, concise code even in functions that can produce multiple kinds of errors.

For production applications, the thiserror crate is very convenient. Its #[derive(Error)] macro automatically generates the Display and Error implementations.

For basic Result operations, see Result::unwrap() / expect() / ? operator.

If you find any errors or copyright issues, please .