Error handling in Rust is one of those topics that can spark passionate debates in the community. After wrestling with various approaches in the iroh codebase, the team has developed some insights about the current state of error handling, the tradeoffs involved, and how to get the best of both worlds.
The Great Error Handling Divide
The Rust ecosystem has largely coalesced around two main approaches to error handling:
The anyhow approach: One big generic error type that can wrap anything. It's fast to implement, gives you full backtraces, and lets you attach context easily. Perfect for applications where you mainly care about "something went wrong" and want good debugging information.
The thiserror approach: Carefully crafted enum variants for every possible error case. This gives you precise error types that consumers can match on and handle differently. It's the approach that many library authors (rightfully) prefer because it provides a stable, matchable API.
Both approaches have their merits, but there's an interesting third option that's rarely discussed: the standard library's IO error model.
Can we have both?
The standard library's approach to IO errors is actually quite elegant. Instead of cramming everything into a single error type or creating hundreds of variants, it splits errors into two components:
Error kind : The broad category of what went wrong (permission denied, not found, etc.)
: The broad category of what went wrong (permission denied, not found, etc.) Error source: Additional context and the original error chain
... continue reading