Rust error handling
Skill Amey-Thakur/AI-SKILLS/skills/systems-languages/rust-error-handling
Plug-and-play skills and prompts for every AI coding agent
npx -y skills add Amey-Thakur/AI-SKILLS --skill rust-error-handlingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 18 days oldThe repository was created 18 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Design Rust error types with the thiserror/anyhow split, context chains, and a deliberate panic policy. Use when structuring errors in Rust libraries and applications.
SKILL.md
2.9 KB, as published. Nobody here has run it
Rust error handling
Result makes every failure path visible in the signature. The design
work is choosing which errors are part of your API (typed, matchable)
and which are just reports for a human (context-rich, opaque).
Method
- Split by audience: libraries type, applications report.
Libraries expose concrete error enums (callers must be able to
match and react);
thiserrorderives the boilerplate. Application and binary code usesanyhow::Result(or eyre-class) where the only consumer is a log line or exit message. The boundary between them is where typed errors get context-wrapped and become reports. - Design library enums for the caller's decisions. One variant
per distinct reaction:
NotFound,PermissionDenied,Retryable(io::Error): not one per internal call site. Mark enums#[non_exhaustive]so adding variants is not a breaking change (see api-change-management thinking); implementstd::error::Errorwith#[source]chains so causes stay walkable. - Add context at every meaningful boundary.
.with_context(|| format!("loading config {path}"))at the point that knows the filename, the query, the request id; the final report then reads as a story ("loading config X: permission denied") instead of a bare OS error. Context laid at each layer is what replaces stack traces in release builds. - Use
?everywhere; convert deliberately.?withFromimpls (thiserror's#[from]) keeps the happy path linear. Resist blanketBox<dyn Error>in public signatures: it types nothing and forces downcasting on callers who needed to match. - Write the panic policy down. Panics are for violated
invariants (bugs), never for expected failure:
unwrap()in library code on I/O or parsing is a defect. Allowed:expect("invariant: queue non-empty after push")documenting why it cannot fail, tests, and prototypes clearly marked. Binaries set a top-level handler to log panics before dying (see error-tracking); servers decide panic=abort vs unwind per their supervisor model. - Test the error paths as API. Assert on matched variants and on user-visible report strings for key failures; error messages are UX (see error-messages) and regress like any other output.
Boundaries
- Do not model expected absence as error:
Optionfor "not there",Resultfor "went wrong"; conflating them blurs every caller's logic. - Cross-FFI boundaries erase Rust errors; translate to codes/strings explicitly at the edge (see ffi-boundaries).
- Async cancellation and task join errors are control flow, not domain errors; handle them at the runtime boundary rather than threading them through domain enums.