rust 51 lines · 9 steps

Building a typed error enum in Rust

A custom enum models every validation failure as a distinct, self-describing error variant.

Explained by highlit
1use std::error::Error;
2use std::fmt;
3 
4#[derive(Debug)]
5pub enum ValidationError {
6 EmptyUsername,
7 UsernameTooLong { len: usize, max: usize },
8 InvalidEmail(String),
9 WeakPassword { reason: &'static str },
10}
11 
12impl fmt::Display for ValidationError {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 match self {
15 ValidationError::EmptyUsername => write!(f, "username must not be empty"),
16 ValidationError::UsernameTooLong { len, max } => {
17 write!(f, "username is {len} characters, but the maximum is {max}")
18 }
19 ValidationError::InvalidEmail(email) => write!(f, "'{email}' is not a valid email address"),
20 ValidationError::WeakPassword { reason } => write!(f, "password is too weak: {reason}"),
21 }
22 }
23}
24 
25impl Error for ValidationError {}
26 
27pub struct Registration {
28 pub username: String,
29 pub email: String,
30 pub password: String,
31}
32 
33pub fn validate(input: &Registration) -> Result<(), ValidationError> {
34 let name = input.username.trim();
35 if name.is_empty() {
36 return Err(ValidationError::EmptyUsername);
37 }
38 if name.len() > 32 {
39 return Err(ValidationError::UsernameTooLong { len: name.len(), max: 32 });
40 }
41 if !input.email.contains('@') || !input.email.contains('.') {
42 return Err(ValidationError::InvalidEmail(input.email.clone()));
43 }
44 if input.password.len() < 8 {
45 return Err(ValidationError::WeakPassword { reason: "must be at least 8 characters" });
46 }
47 if !input.password.chars().any(|c| c.is_ascii_digit()) {
48 return Err(ValidationError::WeakPassword { reason: "must contain a digit" });
49 }
50 Ok(())
51}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Modeling each failure mode as an enum variant lets the compiler enforce exhaustive handling of every error case.
  2. 2Implementing Display plus the Error marker trait makes your type interoperate with the standard error ecosystem.
  3. 3Returning Result with a rich error type pushes failure details to the caller instead of losing them in strings.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a typed error enum in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code