Error Handling Best Practices
How to Use This List
- Libraries: typed errors. Applications: context-rich anyhow/eyre.
- Review before adding
unwrapto production paths.
A - Libraries
- Use
thiserrorfor public error enums. Stable matchable variants. - Implement
Error + Display + Fromfor sources. Enable?chains. - Avoid
anyhowin public APIs. Consumers need typed errors. - Mark extensible enums
#[non_exhaustive]. Semver-friendly evolution. - Document which variants are transient vs permanent. Retry logic depends on it.
B - Applications
- Use
anyhoworeyreat binary boundary. Attach context liberally. - Return non-zero exit codes from CLI. Map
Errto code 1+. - Log full error chain once at boundary. Avoid duplicate context layers.
- Map errors to HTTP status in handlers only. Keep domain errors transport-agnostic.
- Enable backtraces in staging CI failures.
RUST_BACKTRACE=1.
C - Panics and unwrap
- No
unwrapin library fallible paths. ReturnResult. - Use
expectwith message only when invariant documented. Tests and provable logic. - Prefer
?over match boilerplate. Clearer happy path. - Use
debug_assert!for dev invariants. Not user validation. - Never panic across FFI. Return error codes.
D - Options and Results
-
Optionfor optional,Resultfor failure. Do not conflate. - Use combinators before deep match nesting. Readability.
- Collect
Resultiterators with short-circuit awareness. Document partial failure policy. - Add context at operation boundaries. File paths, user ids, request ids.
- Test error paths, not only Ok. Include invalid input tests.
FAQs
Single error type for app?
anyhow::Error common - yes.Retry which errors?
Io timeout yes, parse error no.serde in errors?
Usually skip - errors not serialized.sqlx/axum errors?
Convert at handler edge.logging crate?
tracing::error with %? or display chain.no_std errors?
thiserror no_std or custom enum.Internationalize errors?
Display for users at UI layer - codes in core.Property tests?
Generate invalid inputs for Result paths.lint?
clippy unwrap_used deny in libs.Next?
Collections and iterator pipelines.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+.