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