Error Propagation Patterns
In this page:
Propagating with ? Across Functions
A helper function can propagate an error with ?, letting its caller (or the caller's caller) ultimately decide how to react, rather than making that decision too early.
Example: Propagating with ? Across Functions
fn parse_positive(s: &str) -> Result<i32, String> {
let n: i32 = s.parse().map_err(|_| String::from("not a number"))?;
if n < 0 {
return Err(String::from("must be positive"));
}
Ok(n)
}
fn main() {
println!("{:?}", parse_positive("5"));
println!("{:?}", parse_positive("-3"));
}
Login to try C/C++/Java/PHP code in the editor
Using Box<dyn Error> for Multiple Error Types
When a function can fail in multiple unrelated ways (e.g. parsing errors and custom validation errors), returning Box<dyn std::error::Error> lets it unify them under one flexible return type.
Example: Using Box<dyn Error> for Multiple Error Types
use std::error::Error;
fn parse_and_check(s: &str) -> Result<i32, Box<dyn Error>> {
let n: i32 = s.parse()?;
Ok(n * 2)
}
fn main() -> Result<(), Box<dyn Error>> {
let value = parse_and_check("21")?;
println!("Value: {}", value);
Ok(())
}
Login to try C/C++/Java/PHP code in the editor
Adding Context While Propagating
A middle-layer function can catch an error, wrap it with more context using map_err, and then propagate the enriched error further up, giving callers a clearer picture of what happened.
Example: Adding Context While Propagating
fn load_setting(raw: &str) -> Result<i32, String> {
raw.parse::<i32>().map_err(|e| format!("failed to load setting: {}", e))
}
fn main() {
match load_setting("abc") {
Ok(v) => println!("Setting: {}", v),
Err(e) => println!("{}", e),
}
}
Login to try C/C++/Java/PHP code in the editor
main Returning a Result
Rust's main function itself can return a Result, allowing the top-level program to use ? directly and print a clean error message automatically if something fails.
Example: main Returning a Result
fn main() -> Result<(), std::num::ParseIntError> {
let value: i32 = "99".parse()?;
println!("Parsed: {}", value);
Ok(())
}
Login to try C/C++/Java/PHP code in the editor
- Handling every possible error deep inside a low-level helper function instead of letting it bubble up to a caller who has more context.
- Forgetting
Box<dyn Error>is a common flexible return type when a function can produce several different unrelated error types. - Overusing
.unwrap()deep in a call chain instead of propagating the error upward with?, which crashes the whole program instead of letting a caller decide.
- Propagating errors upward with
?lets higher-level code decide how to handle or report failures. Box<dyn std::error::Error>is a common return type for functions that may fail in more than one distinct way.- Layered functions can each add their own context before propagating an error further up the call stack.
- Good error propagation keeps low-level functions simple while concentrating decision-making at higher levels.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: