Bibliotecas de Manejo de Errores en Rust

  • thiserror proporciona macros derivadas convenientes para tipos de error personalizados.

  • snafu es un marco de manejo y reporte de errores con contexto.

  • anyhow es una biblioteca flexible de manejo y reporte de errores.

thiserror vs snafu

thiserror

thiserror es una biblioteca ligera que proporciona macros derivadas para simplificar definiciones de error.

Características:

  • Sintaxis concisa con poca ceremonia
  • Adecuada para crear bibliotecas de tipos de error y APIs
  • Típicamente usada para crear bibliotecas destinadas a otros
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataError {
    #[error("Error de base de datos: {0}")]
    DatabaseError(#[from] sqlx::Error),
    
    #[error("Error de validación: {0}")]
    ValidationError(String),
    
    #[error("Registro no encontrado")]
    NotFound,
}

snafu

snafu proporciona un marco de manejo de errores más completo con enfoque en contexto y encadenamiento de errores.

Características:

  • Fomenta la adición de contexto más preciso mediante el patrón "selector de contexto"
  • Promueve el patrón "un enum de error por módulo"
  • Soporta variantes de error tanto estilo struct como tuple
  • Soporte integrado para backtraces
use snafu::{Snafu, ResultExt, Backtrace};

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Error al leer archivo de configuración {filename:?}"))]
    ReadConfig {
        filename: String,
        source: std::io::Error,
        backtrace: Backtrace,
    },
    
    // También se soporta estilo tuple
    #[snafu(display("Error de E/S"))]
    Io(#[snafu(source)] std::io::Error, #[snafu(backtrace)] Backtrace),
}

// Ejemplo de selector de contexto
fn read_config(path: &str) -> Result<Config, Error> {
    std::fs::read_to_string(path).context(ReadConfigSnafu { filename: path })?;
    // ...
}

Comparación

Característicathiserrorsnafu
Concisión de sintaxisMás concisoMás verboso
Contexto de errorSoporte básicoMecanismos de contexto ricos
Escala adecuadaProyectos pequeños a medianosProyectos medianos a grandes
Líneas por error~2 líneas por error~5 líneas por error
Organización de erroresUsualmente un solo enum de errorFomenta enums de error a nivel de módulo
Soporte de backtraceSin soporte integradoSoporte integrado

Consejos de selección:

  • Elige thiserror cuando necesites tipos de error simples y claros, especialmente en bibliotecas
  • Elige snafu cuando necesites manejo de errores más estructurado, particularmente en aplicaciones grandes

anyhow

anyhow es una biblioteca de manejo de errores diferente a las dos anteriores, enfocándose en aplicaciones más que en bibliotecas.

Características:

  • Diseñada para manejo de errores en aplicaciones, no en bibliotecas
  • Proporciona un tipo dinámico anyhow::Error que puede contener cualquier error que implemente el trait Error
  • Simplifica el manejo entre múltiples tipos de error
  • No requiere definir tipos de error personalizados
use anyhow::{Context, Result};

fn main() -> Result<()> {
    let config = std::fs::read_to_string("config.json")
        .context("Error al leer archivo de configuración")?;
        
    let app_config: AppConfig = serde_json::from_str(&config)
        .context("Formato de configuración inválido")?;
        
    // Usando Result<T> como alias de tipo para Result<T, anyhow::Error>
    Ok(())
}

anyhow vs thiserror/snafu:

  • anyhow se enfoca en manejo de errores durante desarrollo rápido de aplicaciones
  • thiserror/snafu se enfocan en crear jerarquías precisas de tipos de error
  • anyhow se usa típicamente en código de aplicación
  • thiserror/snafu se usan típicamente en código de biblioteca

En la práctica, anyhow y thiserror suelen usarse juntos: las bibliotecas usan thiserror para definir tipos de error precisos, mientras que las aplicaciones usan anyhow para manejar errores de diversas fuentes.