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 {
Ok(T),
Err(E),
}
This T and E mention in here Result
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");
}
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`
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),
}
}
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!");
}
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>
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
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)
- 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
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
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
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 >
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 >
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 >
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 >
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)
- Disable backtraces:
For Linux/Mac (Bash/Zsh):
RUST_BACKTRACE=0 cargo run
For Windows Command Prompt (CMD):
set RUST_BACKTRACE=0
cargo run
Output
thread 'main' panicked at 'Test panic', src\main.rs:2:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
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::().unwrap(); // Panics on Err
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::().expect("Parsing failed"); // Panics with custom message
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 {
let content = fs::read_to_string("config.toml")?;
Ok(content)
}
fn main() -> Result<(), io::Error> {
let config = read_config()?;
println!("Config: {}", config);
Ok(())
}
Helpful Crates
thiserror
: For defining library error types
anyhow
: For application error handling
snafu
: Alternative error handling with backtraces
miette
: Fancy diagnostic error reporting