Skip to content

Instantly share code, notes, and snippets.

@luca992
Last active August 2, 2025 08:08
Show Gist options
  • Select an option

  • Save luca992/ad305d1e39fb9cfeae91bf997607654f to your computer and use it in GitHub Desktop.

Select an option

Save luca992/ad305d1e39fb9cfeae91bf997607654f to your computer and use it in GitHub Desktop.
Rust Snafu Errors Example
use snafu::Snafu;
/// Error type for all API traits
/// Note: Do not put implementation specific errors here (so no errors from reqwest, serde, etc.)
/// These should be generic errors that can be used by any API implementation.
/// The implementation specific errors should be defined locally for each API implementation then
/// converted to this error type before being returned.
///
/// Hint: use [From] to convert implementation specific errors to this error type. You can define
/// an error snafu enum inside the same file as an api implementation and also implement the
/// conversion to this error type in the same file using the [From] trait.
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum ApiError {
#[snafu(display("Connection error: {}", details))]
ConnectionError { details: String },
#[snafu(display("Invalid request: {}", details))]
InvalidRequest { details: String },
#[snafu(display("{}", source))]
InvalidData { source: InvalidDataError },
#[snafu(display("Resource not found: {}", details))]
NotFound { details: String },
#[snafu(display("Resource already exists: {}", details))]
AlreadyExists { details: String },
#[snafu(display("Unexpected response: {}", details))]
UnexpectedResponse { details: String },
#[snafu(display("{}", message))]
Unexpected { message: String },
#[snafu(display("Request failed: {}", details))]
RequestFailed { details: String },
#[snafu(display("Too many requests: {}", details))]
TooManyRequests { details: String },
#[snafu(display("Permission error: {}", source))]
Permission {
source: crate::error::PermissionError,
},
#[snafu(display("Internal error: {}", source))]
Internal {
// Using a boxed trait object so that any error type can be wrapped.
source: Box<dyn std::error::Error + Send + Sync>,
},
}
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum RepositoryError {
#[snafu(display("Entity not found: {details}"))]
NotFound { details: String },
#[snafu(display("Already exists: {details}"))]
AlreadyExists { details: String },
#[snafu(display("Invalid data: {source}"))]
InvalidData { source: InvalidDataError },
#[snafu(display("Unexpected error: {message}"))]
Unexpected { message: String },
}
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum InvalidDataError {
#[snafu(display("Invalid input: {details}"))]
InvalidArg { details: String },
#[snafu(display("Unexpected: {details}"))]
UnexpectedDataState { details: String },
#[snafu(display("Unavailable: {details}"))]
Unavailable { details: String },
#[snafu(display("Parse error: {details}"))]
ParseError { details: String },
#[snafu(display("Serialization error: {details}"))]
SerializationError { details: String },
}
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum PermissionError {
#[snafu(display("Unauthorized: {details}"))]
Unauthorized { details: String },
}
// Helpers
impl PermissionError {
pub fn unauthorized<T: ToString>(details: T) -> Self {
Self::Unauthorized {
details: details.to_string(),
}
}
}
impl InvalidDataError {
pub fn invalid_arg<T: ToString>(details: T) -> InvalidDataError {
InvalidDataError::InvalidArg {
details: details.to_string(),
}
}
pub fn unexpected_data_state<T: ToString>(details: T) -> InvalidDataError {
InvalidDataError::UnexpectedDataState {
details: details.to_string(),
}
}
pub fn unavailable<T: ToString>(details: T) -> InvalidDataError {
InvalidDataError::Unavailable {
details: details.to_string(),
}
}
pub fn parse_error<T: ToString>(details: T) -> InvalidDataError {
InvalidDataError::ParseError {
details: details.to_string(),
}
}
pub fn serialization_error<T: ToString>(details: T) -> InvalidDataError {
InvalidDataError::SerializationError {
details: details.to_string(),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment