| Crates.io | erract |
| lib.rs | erract |
| version | 0.1.2 |
| created_at | 2026-01-07 14:19:17.533606+00 |
| updated_at | 2026-01-18 08:48:35.729925+00 |
| description | Structured, context-aware error handling |
| homepage | |
| repository | https://github.com/ab22593k/erract |
| max_upload_size | |
| id | 2028320 |
| size | 145,336 |
erract provides production-ready error handling that solves:
Two audiences, two needs:
This library combines the best ideas from:
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)))
}
#[track_caller] instead of expensive backtracesCow<'static, str> for static messages// 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"
// 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)
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",...}
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) |
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:
Choose erract when:
Choose anyhow when:
See benches/README.md for detailed benchmark methodology.
This project is licensed under either of
at your option.