M Logo
๐Ÿ“ Rust for Beginners ยท Part 14 of 22

Rust Error Handling Explained: Result, the ? Operator, panic! and expect

November 10, 2026

Welcome to episode 14 of Rust for Beginners, a series for complete beginners (no programming experience needed). In the last video, we learned about Option. Today, we'll learn how Rust handles errors: panic, Result, and the question mark operator. Every code block below is the exact code from the video, ready to copy.

1. New project

Let's create a new project called errors, and open it in VS Code.

bash
cargo new errors
cd errors

2. Two kinds

Rust has two kinds of errors. Some are bugs the program can't recover from. Those panic. Others are expected, like bad user input. Those return a Result.

3. panic!

panic stops the program right away, with a message.

src/main.rs:

rust
fn main() {
    println!("Starting...");
    panic!("Something went terribly wrong!");
}

Output (the thread number changes every run):

text
Starting...

thread 'main' (3533) panicked at src/main.rs:3:5:
Something went terribly wrong!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

4. Run A

Let's run it. We see "Starting", then the panic message, and the line where it happened.

bash
cargo run

5. Result

Result is an enum, like Option. It's either Ok, with a value, or Err, with an error.

6. parse

parse turns text into a number. It can fail, so it returns a Result. We match on it, just like an Option.

rust
fn main() {
    for text in ["42", "abc"] {
        let result: Result<i32, _> = text.parse();
        match result {
            Ok(number) => println!("{text} -> {number}"),
            Err(error) => println!("{text} -> error: {error}"),
        }
    }
}

Output: 42 -> 42 / abc -> error: invalid digit found in string

7. Run B

Let's run it. Forty-two works. "abc" gives an error: invalid digit. And no crash.

bash
cargo run

8. Our own

Our own functions can return a Result too. check age returns the age, or an error message as a String.

rust
fn check_age(text: &str) -> Result<u32, String> {
    let age: u32 = match text.parse() {
        Ok(n) => n,
        Err(_) => return Err(format!("'{text}' is not a number")),
    };
    if age > 150 {
        return Err(format!("{age} is too old"));
    }
    Ok(age)
}

fn main() {
    for text in ["25", "abc", "200"] {
        match check_age(text) {
            Ok(age) => println!("Age: {age}"),
            Err(message) => println!("Error: {message}"),
        }
    }
}

Output: Age: 25 / Error: 'abc' is not a number / Error: 200 is too old

9. Err / Ok

When something's wrong, we return Err. At the end, we wrap the good value in Ok.

10. Run C

Let's run it. Twenty-five is fine, "abc" is not a number, and two hundred is too old.

bash
cargo run

11. ?

Writing match every time gets long. The question mark does it for us. If parse fails, the question mark returns the error from the function right away. If it works, we get the number.

rust
use std::num::ParseIntError;

fn add_strings(a: &str, b: &str) -> Result<i32, ParseIntError> {
    let x: i32 = a.parse()?;
    let y: i32 = b.parse()?;
    Ok(x + y)
}

fn main() {
    println!("{:?}", add_strings("2", "3"));
    println!("{:?}", add_strings("2", "three"));

    let n: i32 = "seven".parse().expect("Please give me a number");
    println!("{n}");
}

Output:

text
Ok(5)
Err(ParseIntError { kind: InvalidDigit })

thread 'main' (3661) panicked at src/main.rs:13:34:
Please give me a number: ParseIntError { kind: InvalidDigit }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

12. Rule

The question mark only works in a function that returns a Result itself.

13. expect

And expect is like unwrap: it gives the value or panics, but with our own message.

14. Run D

Let's run it. Two plus three is Ok five. "three" isn't a number, so we get the Err. And expect panics with our message.

bash
cargo run

Recap

To recap: panic for bugs you can't recover from. Result, with Ok and Err, for errors you expect. The question mark passes errors up. And expect or unwrap only when failing is truly a bug.

ยฉ 2026 All Rights Reserved By Mahmudul Alam