Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Error Propagation, Context, and Messages

Rule

Propagate with ?, preserve source chains, add concise context at operation boundaries, and never stringify a source merely to add context.

Why

Useful chains explain both the failed operation and its cause. Context on every line is repetitive; flattening to text destroys structure.

Do

  • Use ? for ordinary propagation.
  • Use From or #[from] for conversions that need no additional fields.
  • Use .context(...) for static application context and .with_context(...) when formatting values.
  • Add context at command, request, job, service, task, crate, or layer boundaries.
  • Keep typed error messages specific to their local failure.
  • Preserve sources with #[source], #[from], anyhow::Context, or explicit fields.
  • Render the full chain deliberately at the outer boundary.

Avoid

  • Do not annotate every ?.
  • Do not restate the lower-level message in context.
  • Do not use .map_err(|err| err.to_string()) or anyhow!("{err}") for propagation.
  • Do not interpolate a source error into a replacement context string.
  • Do not put secrets or unredacted request data in messages.

Library vs Application

Libraries describe local failures with typed errors. Applications add operation context and choose final CLI, API, worker, or log rendering.

Example

#![allow(unused)]
fn main() {
use anyhow::{Context as _, Result};

fn run(path: &Path) -> Result<()> {
    let config = config_lib::load(path)
        .with_context(|| format!("loading configuration from {}", path.display()))?;
    start_server(config).context("starting server")
}
}

Avoid flattening the chain:

#![allow(unused)]
fn main() {
let config = config_lib::load(path)
    .map_err(|err| anyhow::anyhow!("failed to load config: {err}"))?;
}

Exceptions

  • Add context near a call when no higher boundary can identify the operation.
  • Keep propagation sparse when typed variants already explain the operation.