بنقرة واحدة
application-errors
Propagating and formatting errors in Rust applications with anyhow
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Propagating and formatting errors in Rust applications with anyhow
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Choosing and profiling the global allocator (jemalloc, mimalloc, system) in the backend-service `service` template
Request lifecycle, Tower layer ordering, and scaling choices in the backend-service `service` template
Observability wiring for the backend-service `service` template: metrique wide-event metrics, tracing logs, and optional dial9 runtime profiling
Setting up automated crate releases with release-plz and OIDC trusted publishing
Standard GitHub Actions CI structure for Rust projects using ci-battery-pack
Cross-platform binary builds for GitHub Releases with cargo-binstall support
| name | application-errors |
| description | Propagating and formatting errors in Rust applications with anyhow |
Propagating and formatting errors in binaries, CLI tools, and services.
Prerequisites: This skill references examples from the error battery pack.
cargo install cargo-bp # install the battery-pack CLI cargo bp add error # add anyhow + thiserror to your project
For CLIs and tools, return anyhow::Result from main() to get automatic error printing:
fn main() -> anyhow::Result<()> {
let config = load_config()?;
run(config)
}
For services or when you want control over error formatting, handle errors explicitly:
fn main() {
if let Err(e) = run() {
eprintln!("{e:?}"); // full chain with backtrace
std::process::exit(1);
}
}
When propagating errors, attach context describing what operation was being attempted (not what went wrong, since the source error already says that):
use anyhow::{Context, Result};
fn read_config(path: &str) -> Result<Config> {
let content = std::fs::read_to_string(path)
.with_context(|| format!("failed to read config from \"{path}\""))?;
let config: Config = toml::from_str(&content)
.context("failed to parse config")?;
Ok(config)
}
fn start_server() -> Result<()> {
let config = read_config("server.toml")
.context("failed to initialize server")?;
// ...
Ok(())
}
This produces:
failed to initialize server
Caused by:
0: failed to read config from "server.toml"
1: No such file or directory (os error 2)
.with_context(|| ...) is the lazy variant for expensive format strings. Both also work on Option<T>, converting None into an error.
cargo run --example context-chain -p error-battery-pack
| Formatter | Output |
|---|---|
{:#} | Single line, colon-separated: outer: middle: root cause |
{:?} | Multi-line "Caused by:" chain, plus backtrace if captured |
Use {:#} for structured log fields. Use {:?} for terminal output.
For structured logging with tracing, walk the chain explicitly:
fn error_chain(error: &anyhow::Error) -> Vec<String> {
error.chain().map(|e| e.to_string()).collect()
}
tracing::error!(
error = %err,
causes = ?error_chain(&err),
"request failed"
);
| Variable | Effect |
|---|---|
RUST_BACKTRACE=1 | Capture backtraces on panic |
RUST_LIB_BACKTRACE=1 | Capture backtraces inside anyhow::Error at creation |
RUST_LIB_BACKTRACE=0 | Disable anyhow backtraces even when RUST_BACKTRACE=1 |
For production services, set RUST_BACKTRACE=1 RUST_LIB_BACKTRACE=0. Backtrace capture can be expensive under contention, and under high error rates the overhead can cause cascading latency spikes.
anyhow is the right default, but define a custom error type when you need to branch on the error programmatically:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("not found: {0}")]
NotFound(String),
#[error("invalid input")]
BadRequest(#[source] anyhow::Error),
#[error("internal error")]
Internal(#[from] anyhow::Error),
}
impl AppError {
pub fn status_code(&self) -> u16 {
match self {
Self::NotFound(_) => 404,
Self::BadRequest(_) => 400,
Self::Internal(_) => 500,
}
}
}
// Wire into your HTTP framework's error response trait
// (e.g., axum's IntoResponse, actix's ResponseError)
This composes with anyhow: library layers use anyhow::Result with .context(), and the outer handler maps into AppError at the boundary. #[from] anyhow::Error acts as a catch-all for unexpected failures.
For errors that cross crate boundaries or need semver stability, see the library-errors skill.