erract

Crates.ioerract
lib.rserract
version0.1.2
created_at2026-01-07 14:19:17.533606+00
updated_at2026-01-18 08:48:35.729925+00
descriptionStructured, context-aware error handling
homepage
repositoryhttps://github.com/ab22593k/erract
max_upload_size
id2028320
size145,336
Abdulwahab (ab22593k)

documentation

README

erract - Structured Error Handling for Rust

Crates.io Documentation License

erract provides production-ready error handling that solves:

  • Actionable errors: Categorized by what callers can do (retry, fail, etc.)
  • Explicit retry semantics: No guessing from error messages
  • Rich context: Automatic location capture with zero overhead
  • Type safety: Enforce context at module boundaries

Philosophy

Two audiences, two needs:

  • Machines: Need flat structures, clear error kinds, predictable codes
  • Humans: Need rich context, call paths, business-level information

This library combines the best ideas from:

Quick Start

use erract::prelude::*;

fn process_user(id: u32) -> erract::Result<String> {
    // Use static constructors for zero-allocation common errors
    let user = lookup_user(id)
        .or_raise(|| Error::not_found())?
        .ok_or_else(|| {
            Error::permanent(ErrorKind::NotFound, format!("user {} not found", id))
                .with_context("user_id", id.to_string())
                .raise()
        })?;

    Ok(user)
}

fn lookup_user(id: u32) -> erract::Result<Option<String>> {
    if id == 0 {
        // Static message - zero allocation
        return Err(Error::not_found().raise());
    }
    Ok(Some(format!("User{}", id)))
}

Features

  • High-performance Context Arena: Thread-local storage for dynamic context, making large-scale context addition up to 40% faster than alternatives.
  • Zero runtime overhead: Uses #[track_caller] instead of expensive backtraces
  • Domain-specific errors: HTTP, Database, and Storage error kinds
  • Error trees: Support for multiple concurrent failures
  • Type safety: Compiler enforces context at module boundaries
  • Zero-copy static strings: Use Cow<'static, str> for static messages
  • Optimized serialization: Fast JSON and machine-readable output

API Highlights

Static Constructors (Zero Allocation)

// Common errors with pre-defined static messages
let err = Error::not_found();           // "not found"
let err = Error::timeout();             // "operation timed out"
let err = Error::permission_denied();   // "permission denied"
let err = Error::validation_failed();   // "validation failed"
let err = Error::unexpected();          // "unexpected error"

Context Methods

// For string context (zero-copy for static strings)
error.with_context("key", "value")

// For non-string values (uses ToString)
error.with_context_value("count", 42)

Serialization

let error = Error::not_found()
    .with_context("resource", "user")
    .with_operation("fetch");

// Human-readable
println!("{}", error);  // "not found (operation: fetch) [resource: user]"

// Machine-readable
error.to_machine_string()  // "kind=not_found;status=permanent;message=not found;..."

// JSON (optimized, ~220ns)
error.to_json()  // {"kind":"not_found","status":"permanent",...}

Comparison with anyhow

erract and anyhow serve different use cases:

Aspect erract anyhow
Design Goal Production services with structured errors Quick prototyping, application code
Retry Semantics Explicit (is_retryable(), is_permanent()) None (manual parsing)
Error Kind Structured enum (ErrorKind) Dynamic (downcast required)
Context Model Key-value pairs String messages
Machine Output Built-in JSON, machine strings Manual formatting
Location Tracking #[track_caller] (zero cost) Backtrace (optional overhead)

Performance Benchmarks

Run cargo bench to reproduce. Results on Linux x86_64:

Benchmark erract anyhow Winner
Basic error creation 22 ns 30 ns erract (+27%)
Formatted error 81 ns 106 ns erract (+24%)
Single context 24 ns 58 ns erract (+59%)
Triple context 110 ns 115 ns erract (+4%)
Large context (100) 13.5 µs 22.9 µs erract (+41%)
to_string 268 ns 52 ns anyhow
to_json 221 ns N/A erract only
is_retryable() check <1 ns N/A erract only

Key Insights:

  • erract excels at error creation, high-pressure context addition (via Arena), and structured queries
  • anyhow excels at deep error propagation and human-only display formatting
  • Memory: erract::Error is 112 bytes (structured), anyhow::Error is 8 bytes (pointer)
  • Trade-off: erract uses more stack space and thread-local memory to achieve superior performance in context-heavy scenarios

When to Choose

Choose erract when:

  • Building production services with retry logic
  • Need machine-parseable errors for alerting/metrics
  • Want explicit error semantics at compile time
  • Multiple teams consume your error data

Choose anyhow when:

  • Building CLI tools or quick prototypes
  • Error handling is human-only (logs, not machines)
  • Minimal boilerplate is priority
  • Don't need structured error classification

See benches/README.md for detailed benchmark methodology.

License

This project is licensed under either of

at your option.

Commit count: 8

cargo fmt