DEV Community

Cover image for Rust Error Handling
Sureni Dhanasekara
Sureni Dhanasekara

Posted on

Rust Error Handling

Rust groups errors into two major categories:

  • recoverable errors
  • unrecoverable error

Recoverable Errors

When it is recoverable error then problem will report to the user and and retry the operation. This errors handle with the type Result since exception is not available in rust.

Ex: File not found error

Unrecoverable Errors

Unrecoverable errors are always symptoms of bugs. This errors handle with the panic! macro and it will stop execution.

Ex: trying to access a location beyond the end of an array.

Recoverable Errors with Result

Result enum is defined as having two variants, Ok and Err, as follows:

 enum Result<T, E> { Ok(T), Err(E), } 
Enter fullscreen mode Exit fullscreen mode

This T and E mention in here Result<T, E> are generic type parameters.
T represent the type of value that will be return in success case and E represent the type of value that will be return in error/failure case.

use std::fs::File; fn main() { let f:u32 = File::open("program.txt"); } 
Enter fullscreen mode Exit fullscreen mode
 error[E0308]: mismatched types --> src/main.rs:4:18 | 4 | let f: u32 = File::open("hello.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found enum `std::result::Result` | = note: expected type `u32` found type `std::result::Result<std::fs::File, std::io::Error>` 
Enter fullscreen mode Exit fullscreen mode

We can modify code as follows to handle error:

use std::fs::File; use std::io::Error; fn main() { let f = File::open("program.txt"); match f { Ok(_file) => println!("File opened successfully"), Err(e) => println!("Error opening file: {}", e), } } 
Enter fullscreen mode Exit fullscreen mode

Unrecoverable Errors with panic!

When the panic! macro executes, your program will print a failure message, unwind and clean up the stack, and then quit.

unwind - Rust walks back up the stack and cleans up the data from each function it encounters.
abort - Ends the program without cleaning up. Memory that the program was using will then need to be cleaned up by the operating system.

if you are using abort then need to do modification in Cargo.toml as follows:
panic = 'abort'

fn main() { panic!("This is an unrecoverable error!"); } 
Enter fullscreen mode Exit fullscreen mode

Output:

Compiling testing v0.1.0 (C:\Users\Sanija Methsen\Desktop\Rust\my-projects\testing) Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.93s Running `target\debug\testing.exe` thread 'main' panicked at src\main.rs:2:5: This is an unrecoverable error! note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: process didn't exit successfully: `target\debug\testing.exe` (exit code: 101) PS C:\Users\Sanija Methsen\Desktop\Rust\my-projects\testing> 
Enter fullscreen mode Exit fullscreen mode

Using a panic! Backtrace
A backtrace is a detailed report showing the sequence of function calls that occurred before the panic, which is extremely helpful for debugging.

  • Enable full backtraces:
For Linux/Mac (Bash/Zsh): RUST_BACKTRACE=1 cargo run For Windows Command Prompt (CMD): set RUST_BACKTRACE=1 cargo run 
Enter fullscreen mode Exit fullscreen mode

Output

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s Running `target\debug\testing.exe` thread 'main' panicked at src\main.rs:2:5: This is an unrecoverable error! note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: process didn't exit successfully: `target\debug\testing.exe` (exit code: 101) 
Enter fullscreen mode Exit fullscreen mode
  • Enable full backtraces with more details:
For Linux/Mac (Bash/Zsh): RUST_BACKTRACE=full cargo run For Windows Command Prompt (CMD): set RUST_BACKTRACE=full cargo run 
Enter fullscreen mode Exit fullscreen mode

Output

Compiling testing v0.1.0 (C:\Users\Sanija Methsen\Desktop\Rust\my-projects\testing) Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.10s Running `target\debug\testing.exe` thread 'main' panicked at src\main.rs:2:5: This is an unrecoverable error! stack backtrace: 0: 0x7ff767896511 - std::backtrace_rs::backtrace::win64::trace at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\..\..\backtrace\src\backtrace\win64.rs:85 1: 0x7ff767896511 - std::backtrace_rs::backtrace::trace_unsynchronized at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66 2: 0x7ff767896511 - std::sys::backtrace::_print_fmt at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\backtrace.rs:66 3: 0x7ff767896511 - std::sys::backtrace::impl$0::print::impl$0::fmt at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\backtrace.rs:39 4: 0x7ff7678a299a - core::fmt::rt::Argument::fmt at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\core\src\fmt\rt.rs:177 5: 0x7ff7678a299a - core::fmt::write at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\core\src\fmt\mod.rs:1449 6: 0x7ff7678948e7 - std::io::Write::write_fmt<std::sys::pal::windows::stdio::Stderr> at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\io\mod.rs:1890 7: 0x7ff767896355 - std::sys::backtrace::BacktraceLock::print at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\backtrace.rs:42 8: 0x7ff767897892 - std::panicking::default_hook::closure$0 at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:298 9: 0x7ff767897683 - std::panicking::default_hook at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:325 10: 0x7ff76789837f - std::panicking::rust_panic_with_hook at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:831 11: 0x7ff7678981d2 - std::panicking::begin_panic_handler::closure$0 at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:697 12: 0x7ff767896c4f - std::sys::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure_env$0,never$> at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\sys\backtrace.rs:168 13: 0x7ff767897e0e - std::panicking::begin_panic_handler at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:695 14: 0x7ff7678a7551 - core::panicking::panic_fmt at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\core\src\panicking.rs:75 15: 0x7ff76789118b - testing::main at C:\Users\Sanija Methsen\Desktop\Rust\my-projects\testing\src\main.rs:2 16: 0x7ff76789106b - core::ops::function::FnOnce::call_once<void (*)(),tuple$<> > at C:\Users\Sanija Methsen\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\ops\function.rs:250 17: 0x7ff76789113e - core::hint::black_box at C:\Users\Sanija Methsen\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\hint.rs:477 18: 0x7ff76789113e - std::sys::backtrace::__rust_begin_short_backtrace<void (*)(),tuple$<> > at C:\Users\Sanija Methsen\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\sys\backtrace.rs:152 19: 0x7ff767891121 - std::rt::lang_start::closure$0<tuple$<> > at C:\Users\Sanija Methsen\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:199 20: 0x7ff767892d5c - std::rt::lang_start_internal::closure$0 at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\rt.rs:168 21: 0x7ff767892d5c - std::panicking::try::do_call at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:587 22: 0x7ff767892d5c - std::panicking::try at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panicking.rs:550 23: 0x7ff767892d5c - std::panic::catch_unwind at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\panic.rs:358 24: 0x7ff767892d5c - std::rt::lang_start_internal at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library\std\src\rt.rs:164 25: 0x7ff76789110a - std::rt::lang_start<tuple$<> > at C:\Users\Sanija Methsen\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\std\src\rt.rs:198 26: 0x7ff7678911a9 - main 27: 0x7ff7678a5ec0 - invoke_main at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78 28: 0x7ff7678a5ec0 - __scrt_common_main_seh at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 29: 0x7ffe69e0259d - BaseThreadInitThunk 30: 0x7ffe6b14af38 - RtlUserThreadStart error: process didn't exit successfully: `target\debug\testing.exe` (exit code: 101) 
Enter fullscreen mode Exit fullscreen mode
  • Disable backtraces:
For Linux/Mac (Bash/Zsh): RUST_BACKTRACE=0 cargo run For Windows Command Prompt (CMD): set RUST_BACKTRACE=0 cargo run 
Enter fullscreen mode Exit fullscreen mode

Output

thread 'main' panicked at 'Test panic', src\main.rs:2:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace 
Enter fullscreen mode Exit fullscreen mode

Unwrap and expect
unwrap will return the value inside the Ok. If the Result is the Err variant, unwrap will call the panic! macro for us.

let num = "42".parse::<i32>().unwrap(); // Panics on Err 
Enter fullscreen mode Exit fullscreen mode

Using expect instead of unwrap and providing good error messages can convey your intent and make tracking down the source of a panic easier.

let num = "42".parse::<i32>().expect("Parsing failed"); // Panics with custom message 
Enter fullscreen mode Exit fullscreen mode

Propagating Errors
Error propagation is a fundamental concept in Rust that allows errors to be passed up the call stack to be handled by calling functions. The ? operator is Rust's primary mechanism for error propagation:

use std::fs; use std::io; fn read_config() -> Result<String, io::Error> { let content = fs::read_to_string("config.toml")?; Ok(content) } fn main() -> Result<(), io::Error> { let config = read_config()?; println!("Config: {}", config); Ok(()) } 
Enter fullscreen mode Exit fullscreen mode

Helpful Crates
thiserror: For defining library error types
anyhow: For application error handling
snafu: Alternative error handling with backtraces
miette: Fancy diagnostic error reporting

Top comments (0)