anyhow
anyhow provides anyhow::Result<T> and context attachments for application binaries where error taxonomy is not part of the public API.
Recipe
[dependencies]
anyhow = "1"use anyhow::{Context, Result};
fn read_port(path: &str) -> Result<u16> {
let s = std::fs::read_to_string(path)
.with_context(|| format!("reading {path}"))?;
let port: u16 = s.trim().parse().context("parsing port")?;
Ok(port)
}When to reach for this: CLIs, servers, and binaries - not published library error types.
Working Example
fn main() -> anyhow::Result<()> {
let port = read_port("PORT")?;
println!("port={port}");
Ok(())
}What this demonstrates:
mainreturnsanyhow::Result?propagates with context chain- Single error type erases specifics at boundary
Deep Dive
anyhow::Error is Send + Sync + 'static, supports downcasting in tests via downcast_ref.
Gotchas
- anyhow in library public API - Consumers cannot match errors. Fix:
thiserrorenum. - Relying on Display text in tests - Fragile. Fix: Downcast or structured tests at boundary.
- Context closure allocation -
with_context(|| ...)lazy. Fix: Usecontextfor static strings. - Mixing anyhow and custom errors - Use
?withFromor.map_err(Into::into). - No backtrace by default - Enable
RUST_BACKTRACE+ anyhow feature flags.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
thiserror | Library crates | Quick internal tool |
eyre | Similar app errors | Team uses anyhow |
Box<dyn Error> | Minimal dep | Context chain wanted |
FAQs
Library use?
Avoid in public signatures.Downcast?
`if let Some(e) = err.downcast_ref::<IoError>()`.ensure! macro?
Assert-like with anyhow bail.bail!?
Early return with error message.Chain display?
Context prints in cause chain.async?
Works in async main and fns.wasm?
Supported.vs eyre?
Similar; anyhow more common in ecosystem.Convert thiserror?
`?` into anyhow at app boundary.Features?
backtrace feature optional.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.