Use thiserror to define custom error types that implement std::error::Error for your public APIs, and use anyhow to handle errors internally without defining custom types. thiserror generates the Error trait implementation via a derive macro, while anyhow provides a flexible Result type that can hold any error.
use thiserror::Error;
use anyhow::Result;
#[derive(Error, Debug)]
#[error("Failed to parse: {0}")]
pub struct ParseError(String);
fn internal_logic() -> Result<()> {
// Any error type works here
if false { Err(anyhow::anyhow!("oops")) } else { Ok(()) }
}
fn public_api() -> Result<(), ParseError> {
// Must return the specific custom error
internal_logic().map_err(|e| ParseError(e.to_string()))
}