Skip to main content
Lesson 3 of 3Beginner⏱ 10 mins

Result, Option, and Errors

Idiomatic error handling in Rust web apps.

67% of path

Learning Objectives

  • Use Result in handlers
  • Use ? operator

##No null, no exceptions

Rust has no null and no exceptions. Instead, two ordinary enums make absence and failure explicit in the type system: Option<T> and Result<T, E>. Once you are comfortable with them, error handling in Actix Web feels natural.

#Option: a value that may be missing

code_blocksrust
enum Option<T> {
    Some(T),
    None,
}

A function that might not find something returns an Option:

code_blocksrust
fn find_user(id: u32) -> Option<String> {
    if id == 1 { Some("Ada".to_string()) } else { None }
}

fn main() {
    match find_user(1) {
        Some(name) => println!("found {name}"),
        None => println!("no such user"),
    }
}

The compiler forces you to handle None, so you cannot forget the missing case and crash with a null pointer.

#Result: an operation that may fail

code_blocksrust
enum Result<T, E> {
    Ok(T),
    Err(E),
}
code_blocksrust
fn parse_age(text: &str) -> Result<u32, std::num::ParseIntError> {
    text.parse::<u32>()
}

#Handy methods

You rarely need a full match. These helpers cover most cases:

code_blocksrust
let name = find_user(2).unwrap_or("guest".to_string());   // default value
let len = find_user(1).map(|n| n.len());                  // transform inside
let user = find_user(2).ok_or("not found")?;             // Option -> Result
let age = parse_age("42").unwrap_or(0);
  • map transforms the inner value.
  • unwrap_or / unwrap_or_else give a default.
  • ok_or turns an Option into a Result.
  • and_then chains operations that may fail.

#The ? operator

Inside a function that returns Result, the ? operator returns the error early, or unwraps the success value:

code_blocksrust
fn double(text: &str) -> Result<u32, std::num::ParseIntError> {
    let n = text.parse::<u32>()?;   // returns Err immediately if parsing fails
    Ok(n * 2)
}

#Why this matters in Actix Web

Handlers can return Result<HttpResponse, MyError>, and ? converts failures into proper HTTP responses. Extractors use Option for optional query fields. Avoid unwrap() and expect() in request handling code: they panic, and a panic means a 500 error instead of a helpful message.

"What If?" Experiment

Learning by doing. Modify the code to see what happens.

Goal

Convert an Option into a Result.

Starting Code
let user = find_user(2);
Suggested Modification

Use find_user(2).ok_or("not found") and print the result.

Expected Result

You get Err("not found") instead of None.

Explanation: ok_or attaches an error value to None, which is how a missing record becomes a 404 in a handler.

Common Mistakes

Anticipate and avoid these frequent pitfalls when working with this concept.

!

Calling unwrap on user-controlled data

A missing or malformed value causes a panic and a 500 response.

Incorrect Pattern
let id: u32 = text.parse().unwrap();
Correct Pattern
let id: u32 = text.parse().map_err(|_| ApiError::BadRequest)?;

Explanation: Convert the failure into your error type and return it. The client gets a clear 400 instead of a crash.

!

Using ? in a function that returns ()

? needs the function to return a Result or Option to carry the error.

Incorrect Pattern
fn run() { let n: u32 = "5".parse()?; }
Correct Pattern
fn run() -> Result<(), std::num::ParseIntError> { let n: u32 = "5".parse()?; Ok(()) }

Explanation: Change the return type to Result so the error has somewhere to go.

Practical Exercise

Parse safely with Result

Task

Write parse_and_double that returns Err for invalid text and the doubled number otherwise, using ?.

Requirements

  • Return Result<u32, std::num::ParseIntError>
  • Use the ? operator
  • Print the result for "21" and "abc"

Need a hint?

Try solving the exercise in your local environment first. Once you have a solution, or if you get completely stuck, reveal the answer.

Real-World Application

Every layer of a production service, from request parsing to database access, returns Result. The ? operator chains them together so a failure at any step becomes a single well-formed HTTP error.

Key Takeaways

  • Option<T> is Some(value) or None; Result<T, E> is Ok(value) or Err(error).
  • ? returns the error early and keeps the happy path clean.
  • map, unwrap_or and ok_or cover most everyday needs.
  • Do not unwrap in handlers; return a Result with a proper error instead.

Finished reading?

Mark this lesson as done to track your progress and earn XP.