Error Stacking in Rust

Rust error stacking & context

  • Core goal: errors should tell humans what went wrong in domain terms, not just where. Stacked/ layered errors with added context at each level are preferred.
  • Example style: decode_msg(...).context(DecodeMessage)? to wrap low‑level errors; some functions (verify_msg) propagate directly.
  • One strategy: many small, specific error types (even per function) to preserve context without lints; the type system then forces explicit decisions.

thiserror, SNAFU, error-stack, anyhow

  • thiserror:
    • Auto‑conversion via #[from] seen by several as an antipattern; it encourages “just bubble up” without context.
    • You can have multiple variants for the same source error if you don’t use #[from] and instead map manually, adding fields like paths, operation names, etc.
  • SNAFU:
    • Designed to make contextual error variants the default.
    • Provides attributes for transparent wrapping and for “implicit” fields (location, backtrace, or custom data like timestamps).
    • Works nicely with things like SpanTrace and avoids closures/clone boilerplate.
  • error-stack and similar crates wrap errors in a Report, stacking context plus optional backtraces/spantraces and attachments, with emphasis on good output formatting.
  • anyhow + small macros (e.g., h!() inserting file/line) are used as lightweight “just work” solutions.

Backtraces, debug info, and performance

  • Debate over whether enabling backtraces meaningfully requires full debug info.
  • Some argue only unwind info (.eh_frame) and symbol tables are needed; full debuginfo is large but can be split out and resolved offline.
  • Others note Rust’s current backtrace API resolves symbols at runtime, offers limited raw-address access, and debug info can be huge and fragile on some platforms.

Result vs exceptions, checked exceptions, and panics

  • Many note Result + ? resembles checked exceptions; some see near‑equivalence, others stress key differences:
    • Explicit appearance in types and callsites vs hidden control flow.
    • Better fit with functional combinators (map, map_err) and pattern matching.
  • Some argue default propagation + automatic stack traces is “just exceptions”; others insist the value is being forced to choose at each boundary.
  • Panics are framed as Rust’s unchecked exceptions, acceptable for programmer bugs or invariant violations, while Result is for expected domain failures.
  • There’s extensive disagreement over how much stack trace info belongs in Result errors vs panics, and over the real merits of Java‑style checked exceptions.

Developer ergonomics & ecosystem

  • Several comments criticize Rust’s error‑handling ergonomics and ecosystem fragmentation; others respond that patterns and libraries are still maturing.
  • A recurring theme: tension between rich, contextual, “semantic stack traces” and ease of use / boilerplate.