Back to list
gar-ai

rust-error-handling

by gar-ai

1🍴 0📅 Dec 31, 2025

SKILL.md


name: rust-error-handling description: Design error types using thiserror for libraries and anyhow for applications. Use when defining error hierarchies or handling fallible operations.

Error Handling

Use thiserror for libraries (structured errors) and anyhow for applications (context-rich errors).

Library Pattern: thiserror

use thiserror::Error;

#[derive(Error, Debug)]
pub enum ProcessingError {
    #[error("Database error: {0}")]
    Database(#[from] sqlx::Error),

    #[error("S3 error: {0}")]
    S3(String),

    #[error("Media extraction error: {0}")]
    MediaExtraction(String),

    #[error("Python execution error: {0}")]
    Python(String),

    #[error("Configuration error: {0}")]
    Config(String),

    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    #[error("Serialization error: {0}")]
    Serialization(#[from] serde_json::Error),
}

// Type alias for ergonomics
pub type Result<T> = std::result::Result<T, ProcessingError>;

Key thiserror Features

#[derive(Error, Debug)]
pub enum MyError {
    // Automatic From implementation
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),

    // Transparent wrapper (delegates Display/source)
    #[error(transparent)]
    Other(#[from] anyhow::Error),

    // Formatted message with fields
    #[error("Failed to process {path}: {reason}")]
    ProcessFailed { path: String, reason: String },

    // Source error without From
    #[error("Database query failed")]
    Query(#[source] sqlx::Error),
}

Application Pattern: anyhow

use anyhow::{Context, Result, bail, ensure};

fn load_config(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .context("Failed to read config file")?;

    let config: Config = serde_json::from_str(&content)
        .with_context(|| format!("Failed to parse config from {}", path))?;

    ensure!(config.is_valid(), "Invalid configuration");

    Ok(config)
}

fn process() -> Result<()> {
    if something_wrong {
        bail!("Something went wrong: {}", details);
    }
    Ok(())
}

Error Propagation

// Use ? for automatic conversion
fn process_video(path: &Path) -> Result<Video> {
    let data = std::fs::read(path)?;           // io::Error -> ProcessingError
    let video = parse_video(&data)?;           // ParseError -> ProcessingError
    Ok(video)
}

// Add context when propagating
fn load_and_process(path: &Path) -> Result<Video> {
    let video = process_video(path)
        .map_err(|e| ProcessingError::MediaExtraction(
            format!("Failed to process {}: {}", path.display(), e)
        ))?;
    Ok(video)
}

Domain-Specific Error Hierarchy

// Top-level error enum
#[derive(Error, Debug)]
pub enum AppError {
    #[error("Database error: {0}")]
    Database(#[from] DatabaseError),

    #[error("API error: {0}")]
    Api(#[from] ApiError),
}

// Sub-domain errors
#[derive(Error, Debug)]
pub enum DatabaseError {
    #[error("Connection failed: {0}")]
    Connection(String),

    #[error("Query failed: {0}")]
    Query(#[from] sqlx::Error),

    #[error("Record not found: {0}")]
    NotFound(String),
}

// Conversion between domains
impl From<DatabaseError> for ApiError {
    fn from(e: DatabaseError) -> Self {
        match e {
            DatabaseError::NotFound(id) => ApiError::NotFound(id),
            other => ApiError::Internal(other.to_string()),
        }
    }
}

Retry-Aware Errors

#[derive(Error, Debug)]
pub enum ProcessingError {
    #[error("Temporary error (retryable): {0}")]
    Temporary(String),

    #[error("Permanent error: {0}")]
    Permanent(String),
}

impl ProcessingError {
    pub fn is_retryable(&self) -> bool {
        matches!(self, ProcessingError::Temporary(_))
    }
}

Guidelines

  • Use thiserror for library code (structured, typed errors)
  • Use anyhow for application code (context-rich, flexible)
  • Always derive Debug on error types
  • Use #[from] for automatic conversion from common errors
  • Add context with .context() or .with_context()
  • Create domain-specific error variants
  • Use ? operator instead of .unwrap() or .expect()
  • Consider if errors are retryable

Examples

See hercules-local-algo/src/error.rs for production error hierarchy.

Score

Total Score

60/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon