Error-Handling Skill
thiserror / anyhow design and refactors - an Agent Skill for Rust 1.97.0 services and libraries.
What This Skill Does
Refactors string errors and unwrap chains into thiserror enums in libraries, anyhow::Result in binaries, context via .context(), and Axum IntoResponse mappings. Adds From impls and #[non_exhaustive] where APIs evolve.
When to Invoke
- PR introduces
unwrapin production path - Library exposes
Box<dyn Error> - HTTP 500 returns raw internal messages
- Migrating
failureorerror-chainlegacy code
Inputs
| Input | Why |
|---|---|
| Crate type | lib vs bin policy |
| Error consumers | match vs propagate |
| HTTP exposure | status code mapping table |
| Backtrace policy | RUST_BACKTRACE in prod |
Outputs
error.rsmodule with typed enumsmainreturninganyhow::Result- Handler
Result<T, AppError>withIntoResponse - Test cases for error display redaction
Guardrails
- Libraries never use anyhow in public signatures.
- No
expectin lib - returnResult. - Context at operation boundaries - "loading config", not every line.
- Redact secrets in Display - manual impl when needed.
- Single error enum per crate when practical - avoid fragmentation.
Recipe
rg 'unwrap\(|expect\(' src/ --type rust
cargo clippy -- -D clippy::unwrap_used
cargo test error_Working Example
use axum::{http::StatusCode, response::IntoResponse};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AppError {
#[error("not found")]
NotFound,
#[error(transparent)]
Internal(#[from] anyhow::Error),
}
impl IntoResponse for AppError {
fn into_response(self) -> axum::response::Response {
let status = match self {
AppError::NotFound => StatusCode::NOT_FOUND,
AppError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
};
(status, self.to_string()).into_response()
}
}FAQs
anyhow in tests?
Fine for integration tests; unit tests often assert specific error variants.
snafu migration?
Incremental: new modules use thiserror; wrap legacy at boundaries.
panic for invariant violations?
Only true bugs after validation; user errors stay Result.
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+.