Classify Retryable Errors with an Enum
Model transport, timeout, and validation failures in one error enum, then decide retryability without matching on strings.
Code
use std::error::Error;
use std::fmt;
#[derive(Debug)]
enum AppError {
Transport { endpoint: String, message: String },
Timeout { after_ms: u64 },
Validation { field: &'static str, message: String },
}
impl fmt::Display for AppError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AppError::Transport { endpoint, message } => {
write!(formatter, "transport error for {endpoint}: {message}")
}
AppError::Timeout { after_ms } => {
write!(formatter, "timed out after {after_ms} ms")
}
AppError::Validation { field, message } => {
write!(formatter, "invalid {field}: {message}")
}
}
}
}
impl Error for AppError {}
impl AppError {
fn is_retryable(&self) -> bool {
matches!(
self,
AppError::Transport { .. } | AppError::Timeout { .. }
)
}
}
fn classify(error: &AppError) -> &'static str {
if error.is_retryable() {
"retry with backoff"
} else {
"return to caller"
}
}
fn main() {
let errors = [
AppError::Transport {
endpoint: "/orders".to_string(),
message: "connection reset".to_string(),
},
AppError::Timeout { after_ms: 250 },
AppError::Validation {
field: "email",
message: "missing @".to_string(),
},
];
for error in &errors {
println!("{error} -> {}", classify(error));
if let Some(source) = error.source() {
println!(" source: {source}");
}
}
}
Report a problem with this exampleOpens a pre-filled issue on GitHub.