I wondered what's the difference and when to use them
Thiserror and Anyhow are both extremely popular and useful error handling crates in Rust, but they serve fundamentally different purposes, primarily based on whether you are writing a library or an application (binary).
Breaking it Down
thiserror - For Defining Specific Error Types (Libraries)
- Purpose: To easily create custom, specific error types (usually enums) for your library. It helps you define what errors your library can produce.
- Mechanism: Uses a procedural macro (#[derive(Error)]) to automatically implement the standardstd::error::Errortrait and often thestd::fmt::Displaytrait based on attributes you provide.
- Key Features:- #[error("...")]: Defines the user-facing error message (for- Display). Supports embedding fields.
- #[from]: Automatically generates- From<SomeOtherError>implementations, making it easy to wrap underlying errors from other libraries or standard types (like- std::io::Error).
- #[source]: Specifies the underlying source error for error chaining/reporting.
 
- Use Case: You are writing a library (my-lib) and want to return clear, well-defined errors likeMyLibError::Io(std::io::Error)orMyLibError::Parsing(ParseError). Consumers of your library can thenmatchon these specific error variants to handle them differently.
- Benefit: Creates a stable, explicit error API for your library. Consumers know exactly what kind of errors to expect and can handle them precisely.
Example (thiserror)
use thiserror::Error;
use std::num::ParseIntError;
use std::io;
#[derive(Error, Debug)]
pub enum DataProcessingError {
    #[error("Failed to read data from source")] // Display impl
    IoError(#[from] io::Error), // From<io::Error> impl, source is io::Error
    #[error("Invalid number format in line: {line_content}")]
    ParseError {
        line_content: String,
        #[source] // Underlying source
        source: ParseIntError,
    },
    #[error("Configuration value missing: {key}")]
    MissingConfig { key: String },
    #[error("Unknown data processing error")]
    Unknown,
}
// Function in your library
// fn process_data() -> Result<(), DataProcessingError> {
//   let data = std::fs::read_to_string("data.txt")?; // ? uses the From<io::Error>
//   let number = data.parse::<i32>().map_err(|e| DataProcessingError::ParseError {
//       line_content: data,
//       source: e,
//   })?;
//   // ...
//   Ok(())
// }
anyhow - For Handling Diverse Errors Easily (Applications)
- Purpose: To make error handling and reporting in applications (binaries) simpler, especially when dealing with many different error types from various libraries. It focuses on consuming errors, not defining library-specific ones.
- Mechanism: Provides a single, concrete error type anyhow::Errorwhich is essentially a wrapper around any type that implementsstd::error::Error. It uses "type erasure" – it hides the original error type inside. It also provides theContextextension trait.
- Key Features:- anyhow::Error: A single error type you can return from functions in your application (like- main).
- ?Operator: Works seamlessly. Any- Result<T, E: Error + ...>can be converted into- Result<T, anyhow::Error>using- ?.
- ContextTrait (- use anyhow::Context;): Allows easily adding descriptive context to errors as they propagate up the call stack (- result.context("Failed to read user config")?).
- Backtraces: Can capture and display backtraces (requires environment variable setup).
 
- Use Case: You are writing an application (my-app) that calls functions fromstd::fs,reqwest,serde_json, andmy-lib. You don't want to define dozens ofFromimplementations or hugematchstatements in yourmainfunction just to handle all possible errors. You want to propagate errors easily with?and add context where needed.
- Benefit: Massively reduces boilerplate error handling code in applications. Makes adding context trivial. Provides good error reports with context and potential backtraces.
Example (anyhow)
use anyhow::{Context, Result}; // Use anyhow's Result alias
// Assume DataProcessingError from the thiserror example exists in `my_lib`
// use my_lib::DataProcessingError;
fn load_and_process() -> Result<()> { // Returns anyhow::Result
    let config_data = std::fs::read_to_string("config.toml")
        .context("Failed to read config.toml")?; // Add context with anyhow
    let user_data = reqwest::blocking::get("http://example.com/users")
        .context("Failed to fetch user data")?
        .text()
        .context("Failed to decode user data response")?;
    // Call library function that uses thiserror
    // my_lib::process_data().context("Failed during core data processing")?; // ? converts DataProcessingError to anyhow::Error
    println!("Processed successfully!");
    Ok(())
}
fn main() {
    if let Err(e) = load_and_process() {
        // anyhow::Error provides a nice display format including context and source chain
        eprintln!("Error: {:?}", e); // Example: "Error: Failed during core data processing: Failed to read data from source: No such file or directory (os error 2)"
        // For user-facing errors, use Display: eprintln!("Error: {}", e);
        std::process::exit(1);
    }
}
Summary:
| Feature | thiserror | anyhow | 
|---|---|---|
| Primary Use | Defining error types | Handling errors | 
| Target | Libraries | Applications (Binaries) | 
| Goal | Create specific, typed errors for library API | Simplify error propagation and add context easily | 
| Mechanism | #[derive(Error)]macro | anyhow::Errortype,Contexttrait | 
| Result Type | Result<T, MySpecificErrorEnum> | Result<T, anyhow::Error>(oranyhow::Result<T>) | 
| Flexibility | Less flexible handling (requires matching) | Highly flexible handling (via ?, type erasure) | 
| API Stability | Good for library APIs | Generally not for library public APIs | 
You often use them together: Libraries use thiserror to define their errors, and applications use anyhow to easily handle errors from those libraries (and others) without excessive boilerplate. The ? in an anyhow-using application seamlessly converts a thiserror-defined error into an anyhow::Error.
