Bird
Raised Fist0
Rustprogramming~20 mins

Custom error types in Rust - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Rust Custom Error Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Rust code with a custom error?

Look at this Rust code that defines a custom error and uses it in a function. What will it print?

Rust
use std::fmt;

#[derive(Debug)]
struct MyError {
    details: String,
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error: {}", self.details)
    }
}

impl std::error::Error for MyError {}

fn might_fail(fail: bool) -> Result<&'static str, MyError> {
    if fail {
        Err(MyError { details: String::from("Something went wrong") })
    } else {
        Ok("Success")
    }
}

fn main() {
    match might_fail(true) {
        Ok(msg) => println!("{}", msg),
        Err(e) => println!("{}", e),
    }
}
Apanic occurred: Something went wrong
BError: Something went wrong
CSuccess
DCompilation error due to missing trait implementation
Attempts:
2 left
💡 Hint

Check what the Err variant prints using the Display trait.

❓ Predict Output
intermediate
2:00remaining
What does this Rust code print when no error occurs?

This code uses a custom error type but calls the function with false. What is printed?

Rust
use std::fmt;

#[derive(Debug)]
struct MyError {
    details: String,
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error: {}", self.details)
    }
}

impl std::error::Error for MyError {}

fn might_fail(fail: bool) -> Result<&'static str, MyError> {
    if fail {
        Err(MyError { details: String::from("Something went wrong") })
    } else {
        Ok("Success")
    }
}

fn main() {
    match might_fail(false) {
        Ok(msg) => println!("{}", msg),
        Err(e) => println!("{}", e),
    }
}
ASuccess
BError: Something went wrong
Cpanic occurred: Something went wrong
DCompilation error due to missing trait implementation
Attempts:
2 left
💡 Hint

Look at the Ok branch of the match.

❓ Predict Output
advanced
2:00remaining
What error does this Rust code raise?

This code tries to create a custom error but forgets to implement a trait. What error occurs?

Rust
struct MyError {
    details: String,
}

fn main() {
    let err = MyError { details: String::from("Oops") };
    println!("{}", err);
}
ANo error, prints: Oops
Berror[E0382]: use of moved value: `err`
Cerror[E0277]: `MyError` doesn't implement `std::fmt::Display`
Derror[E0425]: cannot find value `err` in this scope
Attempts:
2 left
💡 Hint

Printing with {} requires the Display trait.

🧠 Conceptual
advanced
2:00remaining
Which statement about custom error types in Rust is true?

Choose the correct statement about creating and using custom error types in Rust.

ACustom error types must implement the <code>std::error::Error</code> trait to be used with <code>Result</code>.
BImplementing <code>std::fmt::Display</code> is optional for custom error types.
CCustom error types can only hold string data and nothing else.
DYou cannot use <code>match</code> to handle custom error types.
Attempts:
2 left
💡 Hint

Think about what traits Rust expects for error handling.

❓ Predict Output
expert
3:00remaining
What is the output of this Rust code with nested custom errors?

This Rust code defines two custom error types and nests one inside the other. What will it print?

Rust
use std::fmt;

#[derive(Debug)]
struct InnerError {
    msg: String,
}

impl fmt::Display for InnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Inner error: {}", self.msg)
    }
}

impl std::error::Error for InnerError {}

#[derive(Debug)]
struct OuterError {
    source: InnerError,
}

impl fmt::Display for OuterError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Outer error caused by: {}", self.source)
    }
}

impl std::error::Error for OuterError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&self.source)
    }
}

fn main() {
    let inner = InnerError { msg: String::from("disk failure") };
    let outer = OuterError { source: inner };
    println!("{}", outer);
}
ACompilation error due to missing lifetime annotations
BInner error: disk failure
COuter error caused by: disk failure
DOuter error caused by: Inner error: disk failure
Attempts:
2 left
💡 Hint

Look at how Display is implemented for OuterError.

Practice

(1/5)
1. What is the main purpose of creating a custom error type in Rust?
easy
A. To automatically fix bugs in the code.
B. To make the program run faster by avoiding errors.
C. To replace the need for using Result types.
D. To describe specific problems in your program with clear error messages.

Solution

  1. Step 1: Understand the role of custom errors

    Custom error types help programmers describe specific problems clearly in their code.
  2. Step 2: Compare with other options

    Custom errors do not speed up code, fix bugs automatically, or replace Result types; they provide clear error descriptions.
  3. Final Answer:

    To describe specific problems in your program with clear error messages. -> Option D
  4. Quick Check:

    Custom error purpose = clear problem description [OK]
Hint: Custom errors explain problems clearly, not fix or speed up code [OK]
Common Mistakes:
  • Thinking custom errors fix bugs automatically
  • Confusing custom errors with performance improvements
  • Believing custom errors replace Result types
2. Which of the following is the correct way to start defining a custom error enum in Rust?
easy
A. enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError) }
B. struct MyError { message: String }
C. fn MyError() -> Error {}
D. class MyError { error: String }

Solution

  1. Step 1: Identify Rust enum syntax

    Rust uses enum to define custom error types with variants, like Io(std::io::Error).
  2. Step 2: Check other options

    struct is for data structures, fn is for functions, and class is not Rust syntax.
  3. Final Answer:

    enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError) } -> Option A
  4. Quick Check:

    Custom error enum = enum with variants [OK]
Hint: Custom errors use enum with variants, not struct or class [OK]
Common Mistakes:
  • Using struct instead of enum for error variants
  • Trying to define errors as functions
  • Using class keyword which is invalid in Rust
3. What will be the output of this Rust code snippet?
use std::fmt;

#[derive(Debug)]
enum MyError {
    NotFound,
    PermissionDenied,
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            MyError::NotFound => write!(f, "Item not found"),
            MyError::PermissionDenied => write!(f, "Permission denied"),
        }
    }
}

fn main() {
    let err = MyError::NotFound;
    println!("Error: {}", err);
}
medium
A. Error: NotFound
B. Error: Item not found
C. Error: Permission denied
D. Compilation error due to missing trait

Solution

  1. Step 1: Understand Display implementation

    The fmt method matches MyError::NotFound and writes "Item not found" to the formatter.
  2. Step 2: Check main output

    Printing err with {} uses Display, so output is "Error: Item not found".
  3. Final Answer:

    Error: Item not found -> Option B
  4. Quick Check:

    Display prints custom message = "Item not found" [OK]
Hint: Display trait controls {} output, matching variant message shown [OK]
Common Mistakes:
  • Expecting Debug output instead of Display
  • Confusing variant name with message
  • Assuming compilation error without Display trait
4. Identify the error in this custom error implementation:
enum MyError {
    Io(std::io::Error),
}

impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}
medium
A. Cannot access self.0 because enum variant is not destructured.
B. Missing implementation of Debug trait.
C. Display trait cannot be implemented for enums.
D. write! macro requires a string literal, not a variable.

Solution

  1. Step 1: Check how self.0 is accessed

    In an enum, you cannot directly access self.0 without matching or destructuring the variant.
  2. Step 2: Understand correct pattern

    You must match self to get the inner std::io::Error value before using it in write!.
  3. Final Answer:

    Cannot access self.0 because enum variant is not destructured. -> Option A
  4. Quick Check:

    Enum variant fields need matching before access [OK]
Hint: Match enum variants before accessing inner fields [OK]
Common Mistakes:
  • Trying to access enum fields directly without match
  • Thinking Display can't be implemented for enums
  • Assuming Debug trait is mandatory for Display
5. You want to create a custom error type that can hold either an IO error or a parsing error, and provide user-friendly messages. Which of these is the best complete approach?
hard
A. Create separate error structs for IO and parse errors without enums, and use panic! for messages.
B. Use a struct with two optional fields for IO and parse errors, and implement Display only.
C. Define an enum with variants for each error type, implement Display with match arms for messages, and implement std::error::Error.
D. Use a type alias for Result with String errors and skip custom error types.

Solution

  1. Step 1: Choose enum for multiple error types

    An enum cleanly groups different error variants like IO and parse errors.
  2. Step 2: Implement Display and std::error::Error traits

    Display provides friendly messages; implementing std::error::Error integrates with Rust error handling.
  3. Final Answer:

    Define an enum with variants for each error type, implement Display with match arms for messages, and implement std::error::Error. -> Option C
  4. Quick Check:

    Enum + Display + Error trait = best custom error pattern [OK]
Hint: Use enum + Display + Error trait for best custom error design [OK]
Common Mistakes:
  • Using struct with optional fields causing confusion
  • Skipping std::error::Error trait implementation
  • Using panic! instead of proper error handling
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard