Sling Academy
Home/Rust/E0131 in Rust: Non-exhaustive patterns when matching a type with `#[non_exhaustive]`

E0131 in Rust: Non-exhaustive patterns when matching a type with `#[non_exhaustive]`

Last updated: January 06, 2025

When working with the Rust programming language, especially when harnessing the power of enums and struct variants, one might encounter the compiler error E0131. This error indicates that a pattern used in a match expression or an if let statement does not account for all possible forms of a non-exhaustive enum or struct. Understanding and resolving this error is crucial for any Rustacean, especially if you are dealing with types marked with #[non_exhaustive].

Understanding #[non_exhaustive]

The #[non_exhaustive] attribute is used in Rust to indicate that there might be future extensions or additional variants in an enum or struct. By marking something as non-exhaustive, library authors signal that more variants might be added over time, which is a good practice for maintaining library versioning and API stability.

Here is a simple example of how a non-exhaustive enum might look:

#[non_exhaustive]
enum AppError {
    NotFound,
    Unauthorized,
    InternalError,
}

When using this enum in match expressions, you must include a wildcard arm (_) to handle any future variants:

fn handle_error(err: AppError) {
    match err {
        AppError::NotFound => println!("Error: Not Found"),
        AppError::Unauthorized => println!("Error: Unauthorized"),
        AppError::InternalError => println!("Error: Internal Error"),
        _ => println!("Error: Unknown"),
    }
}

The Significance of E0131

Error code E0131 appears when the match arms do not cover all possibilities of the non-exhaustive type. It signifies compiler checks that prevent assumptions about future versions of the enum. Here's what happens when such checks aren't meticulously accounted for:

fn handle_other_error(err: AppError) {
    match err {
        AppError::NotFound => println!("Error: Not Found"),
        AppError::Unauthorized => println!("Error: Unauthorized"),
        // missing the catch-all pattern
    }
}
// This code will trigger E0131 because the match arms are not exhaustive.

Strategies to Resolve E0131

To resolve Error E0131, ensure you're covering all possible cases by using the wildcard _ arm:

  • Add a Wildcard Pattern: This is the most straightforward fix—a catch-all branch for anything unexpected or new:
fn handle_error_with_catchall(err: AppError) {
    match err {
        AppError::NotFound => println!("Error: Not Found"),
        AppError::Unauthorized => println!("Error: Unauthorized"),
        AppError::InternalError => println!("Error: Internal Error"),
        _ => println!("Error: Unrecognized or internal error"),
    }
}
  • Refactor to Handle Changes: In some cases, consider refactoring your approach or accepting the responsibility of catching future variants through more general logic.
  • Understand the Contract: When consuming APIs with #[non_exhaustive], embrace the traditional adjustment period with your code so as to prevent future errors and embrace newer versions.

Best Practices

When implementing or dealing with #[non_exhaustive], imagine it as part of a contract between library author and consumer. Follow these best practices:

  • Always implement fallback handlers to capture all future possibilities and to keep your application robust against external API changes.
  • Read documentation and understand the plan for certain APIs; knowing potential future versions answers the challenge of ongoing version compatibility.
  • Keep ongoing tests to anticipate changes in enum variants.

By strategically covering non-exhaustive patterns and complying with the rustc compiler guidelines, one can not only avoid E0131 but also embrace the forward-compatibility principles at the heart of modern Rust coding practices.

Next Article: E0132 in Rust: Partial initializations of uninitialized structures are not allowed

Previous Article: E0124 in Rust: Field is already declared in this struct or variant

Series: Common Errors in Rust and How to Fix Them

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior