Custom Error Types
In this page:
#[derive(Debug)]
enum NameError {
Variant(Type),
}
impl std::fmt::Display for NameError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "message")
}
}
impl std::error::Error for NameError {}
Defining a Custom Error Enum
A custom error type is typically an enum listing every distinct way an operation can fail, giving callers structured information instead of just a generic string.
Example: Defining a Custom Error Enum
// Auto-generate #[derive(Debug)] for the type below
#[derive(Debug)]
// Define an enum `MathError` listing its possible variants
enum MathError {
DivideByZero,
NegativeSquareRoot,
}
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `err`, set to `MathError::DivideByZero`
let err = MathError::DivideByZero;
// Print "{:?}" to the console, substituting in `err` (with a trailing newline)
println!("{:?}", err);
}
Login to try C/C++/Java/PHP code in the editor
Returning a Custom Error from a Function
Functions can return Result<T, MyError> using the custom error type, letting the compiler enforce that every failure case is represented in the enum.
Example: Returning a Custom Error from a Function
// Auto-generate #[derive(Debug)] for the type below
#[derive(Debug)]
// Define an enum `MathError` listing its possible variants
enum MathError {
DivideByZero,
}
// Define the function `divide` taking `a`, `b` and returning a `Result<f64, MathError>`
fn divide(a: f64, b: f64) -> Result<f64, MathError> {
// Check whether `b == 0.0`
if b == 0.0 {
Err(MathError::DivideByZero)
// Otherwise, run this branch
} else {
Ok(a / b)
}
}
// Entry point: execution of the program starts here
fn main() {
// Print "{:?}" to the console, substituting in `divide(10.0, 0.0)` (with a trailing newline)
println!("{:?}", divide(10.0, 0.0));
}
Login to try C/C++/Java/PHP code in the editor
Implementing Display for Readable Messages
Implementing std::fmt::Display for a custom error type gives it a clean, human-readable message when printed with {} instead of just the raw Debug output.
Example: Implementing Display for Readable Messages
// Bring `std::fmt` into scope
use std::fmt;
// Auto-generate #[derive(Debug)] for the type below
#[derive(Debug)]
// Define an enum `MathError` listing its possible variants
enum MathError {
DivideByZero,
}
// Implement methods on `fmt`
impl fmt::Display for MathError {
// Define the function `fmt` taking `&self`, `f` and returning a `fmt::Result`
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Match on `self` and branch by pattern
match self {
MathError::DivideByZero => write!(f, "cannot divide by zero"),
}
}
}
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `err`, set to `MathError::DivideByZero`
let err = MathError::DivideByZero;
// Print "{}" to the console, substituting in `err` (with a trailing newline)
println!("{}", err);
}
Login to try C/C++/Java/PHP code in the editor
Matching on a Custom Error
Because a custom error is an enum, callers can match on it to respond differently to each specific kind of failure, rather than only having a single generic error message.
Example: Matching on a Custom Error
// Auto-generate #[derive(Debug)] for the type below
#[derive(Debug)]
// Define an enum `MathError` listing its possible variants
enum MathError {
DivideByZero,
NegativeSquareRoot,
}
// Define the function `check` taking `n` and returning a `Result<f64, MathError>`
fn check(n: f64) -> Result<f64, MathError> {
// Check whether `n < 0.0`
if n < 0.0 {
Err(MathError::NegativeSquareRoot)
// Otherwise, run this branch
} else {
Ok(n.sqrt())
}
}
// Entry point: execution of the program starts here
fn main() {
// Match on `check(-4.0)` and branch by pattern
match check(-4.0) {
Ok(v) => println!("Root: {}", v),
Err(MathError::NegativeSquareRoot) => println!("Cannot take root of negative number"),
Err(MathError::DivideByZero) => println!("Divide by zero"),
}
}
Login to try C/C++/Java/PHP code in the editor
- Using
Stringfor every error instead of a proper enum, losing the ability for callers to match on specific failure kinds. - Forgetting to implement
std::fmt::Display(and oftenstd::error::Error) so the custom error type prints nicely and interoperates with other error-handling code. - Defining a custom error enum but never deriving or implementing
Debug, which most error-handling code expects.
- A custom error type is usually an enum with one variant per distinct kind of failure.
- Implementing
std::fmt::Displaygives the error type a readable, user-facing message. - Implementing
std::error::Errorlets your custom error interoperate with the wider Rust error-handling ecosystem. - Custom error types let callers
matchon specific failure kinds instead of just a generic message string.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: