anyhow versus thiserror in Rust error handling
idiomatic error-design judgment.
anyhow gives one opaque dynamic error type for applications where you mostly propagate and report; thiserror derives concrete typed enums for libraries so callers can match on variants.
WHAT THIS TESTS It checks whether you understand the community convention for structuring errors based on whether your code is a reusable library or a top-level application.
A GOOD ANSWER COVERS anyhow offers a single, type-erased error type, anyhow::Error, that can wrap any error implementing the standard Error trait. It makes propagation trivial (functions return anyhow::Result<T>), supports attaching human-readable context with .context(...), and captures backtraces. It is aimed at applications and binaries where you generally do not need callers to programmatically distinguish error kinds; you propagate up and report at the top. thiserror is a derive macro that helps you define your own concrete error enum: you annotate variants with display messages and source/from attributes, and it generates the boilerplate Error and Display impls and From conversions. This exposes a precise, matchable set of variants to callers, which is what a library should do so consumers can handle specific failures.
DESIGN TRADE-OFFS anyhow optimizes for convenience and speed of development but erases type information, so callers cannot match on specific causes; that is fine inside an app, harmful in a public API. thiserror keeps errors concrete and stable for callers at the cost of more upfront definition. They compose: a library defines thiserror enums, and an application consuming several libraries can collapse them into anyhow.
COMMON WRONG ANSWERS Saying anyhow and thiserror are interchangeable. Recommending anyhow for a library's public API. Thinking thiserror provides a runtime error type rather than generating impls for yours.
LIKELY FOLLOW-UPS How does the From conversion generated by thiserror cooperate with the ? operator? Can you use both in one workspace? What is the cost of boxing in anyhow?
ONE CONCRETE EXAMPLE A parsing library defines enum ParseError with thiserror, giving variants like UnexpectedEof and InvalidToken that downstream code can match on to recover differently. The command-line application that uses that library returns anyhow::Result<()> from main, propagates ParseError and IO errors alike with ?, attaches context such as .context("reading config"), and prints the resulting chain, never needing to match individual variants itself.
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.