Rust Error Handling
Guide for effective error handling in Rust.
Quick Start
Use Result<T, E> for operations that can fail:
use std::fs;
use std::io;
fn read_username(path: &str) -> Result<String, io::Error> {
let content = fs::read_to_string(path)?;
Ok(content.trim().to_string())
}
The ? operator:
- Returns early on
Err - Automatically converts errors via
Fromtrait - Only works in functions returning
ResultorOption
Error Propagation
Chain operations with ?:
use anyhow::Result;
fn load_config() -> Result<Config> {
let path = find_config_file()?;
let content = fs::read_to_string(path)?;
let config = toml::from_str(&content)?;
Ok(config)
}
Custom Error Types
For libraries - use thiserror:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ConfigError {
#[error("config file not found: {0}")]
NotFound(String),
#[error("invalid config format")]
InvalidFormat(#[from] toml::de::Error),
#[error("io error")]
Io(#[from] std::io::Error),
}
For applications - use anyhow:
use anyhow::{Context, Result};
fn process() -> Result<()> {
let config = load_config()
.context("failed to load config")?;
let data = fetch_data(&config.url)
.context("failed to fetch data")?;
Ok(())
}
Error Context
Add context to errors for better debugging:
use anyhow::{Context, Result};
fn parse_port(s: &str) -> Result<u16> {
s.parse()
.with_context(|| format!("failed to parse port: {}", s))
}
Advanced Patterns
See references/error_patterns.md for:
- Error downcasting
- Multiple error types
- Error recovery strategies
- Testing error conditions
Use scripts/check_error_handling.sh to verify error handling coverage in your codebase.
Best Practices
- Use
Resultfor recoverable errors,panic!for bugs - Add context with
.context()- Makes debugging easier - Define custom errors for libraries - Better API ergonomics
- Use
anyhowfor applications - Simpler error handling - Test error paths - Don't just test the happy path
Converted and distributed by TomeVault — claim your Tome and manage your conversions.