In this lesson, you will learn how to organize complex application failures by nesting smaller error enums within a primary domain error enum.
When building a large application, you often deal with multiple "sub-systems" like a database, an authentication service, and an API client. Instead of flattening all these errors into one giant, unmanageable list, you can structure them hierarchically. This approach keeps your code modular and makes pattern matching much cleaner.
The Nested Strategy
Think of your top-level DomainError as a container. Each variant of this enum corresponds to a functional area of your application, and it carries a specialized error enum as its data payload.
// Sub-system specific errors
enum DatabaseError { ConnectionFailed, QueryTimeout }
enum AuthError { InvalidToken, Unauthorized }
// The high-level domain error
enum AppError {
Database(DatabaseError),
Authentication(AuthError),
Network,
}
By nesting them, you separate concerns. If your business logic layer encounters a DatabaseError, it doesn't need to know about AuthError. When you match on the AppError, you can "drill down" into the specific domain error using nested patterns:
match error {
AppError::Database(db_err) => match db_err {
DatabaseError::ConnectionFailed => println!("Retry DB connection"),
DatabaseError::QueryTimeout => println!("Slow query!"),
},
AppError::Authentication(_) => println!("Redirecting to login..."),
AppError::Network => println!("Check your internet connection."),
}
Why this is powerful
This hierarchy acts as a blueprint for your application's failure modes. Because you are using algebraic data types, Rust forces you to handle every specific sub-error within a domain, preventing you from accidentally ignoring internal details. It also allows your functions to return a Result<T, AppError>, keeping your return types consistent throughout the project while still preserving the granular detail of exactly what went wrong deep in the stack.
By grouping errors logically, you maintain a clean interface that scales as your project grows from a few modules into a massive system.
Key Takeaway: Nesting domain-specific error enums allows you to organize complex failure states into a hierarchical structure that is both easy to traverse and strict to enforce.