Skip to content

anyhow

Developer UtilitiesUtilitiesRust

What it is

anyhow provides a boxed, dynamically typed error for application code, with easy context attachment and a captured backtrace.

Return anyhow::Result<T> and use ? freely across error types. The context method adds human-readable layers describing what was being attempted.

Installation

cargo add anyhow

Getting started

The smallest useful thing you can do with it, and what each part means.

Context that makes logs useful
use anyhow::{Context, Result, bail, ensure};

fn load_config(path: &Path) -> Result<Config> {
    let text = std::fs::read_to_string(path)
        .with_context(|| format!("reading config from {}", path.display()))?;

    let config: Config = toml::from_str(&text)
        .context("parsing config as TOML")?;

    ensure!(config.port > 0, "port must be positive");
    if config.workers == 0 { bail!("workers must be at least 1"); }

    Ok(config)
}

// Error: reading config from /etc/app.toml
// Caused by: No such file or directory (os error 2)
with_context is lazy — the closure only runs on failure, so formatting costs nothing on the happy path. The layered output is what turns an opaque failure into a diagnosable one.

Advanced usage

Where the library earns its place over a simpler alternative.

Recovering a specific error type
fn main() -> anyhow::Result<()> {
    if let Err(e) = run() {
        // Look for a concrete type inside the boxed error.
        if let Some(io) = e.downcast_ref::<std::io::Error>() {
            if io.kind() == std::io::ErrorKind::NotFound {
                return Ok(()); // acceptable
            }
        }
        return Err(e);   // main prints the chain and the backtrace
    }
    Ok(())
}
downcast_ref recovers the underlying type when you do need to branch. Returning anyhow::Result from main gives you the full cause chain printed automatically.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Callers cannot match on the failure
That is the trade-off. If callers need to branch, the function belongs in a library and should use thiserror.
The error message lacks detail
No context was added. Attach .context() at each boundary describing what was being attempted.

Best practices

  • Use anyhow in binaries and thiserror in libraries; do not expose anyhow in a public API.
  • Add context at each layer — the chain is what makes production errors debuggable.
  • Prefer with_context over context when the message needs formatting; it avoids the cost on success.
  • Set RUST_BACKTRACE=1 to get a backtrace attached automatically.

Background

Why it exists, and what it was reacting to.

The companion to thiserror, also by David Tolnay. In an application you usually only want to report an error, not match on it — anyhow removes the boilerplate of enumerating every failure.