Rust error handling
Skill fusengine/agents/plugins/rust-expert/skills/rust-error-handling
Redefining development through cognitive automation and collaborative agent systems.
npx -y skills add fusengine/agents --skill rust-error-handlingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 22 stars22 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
Use when designing Rust error handling — picking thiserror for libraries vs anyhow for applications, building typed error enums, converting errors with #[from], and deciding recoverable errors vs panics. Do NOT use for general ownership/borrowing (use rust-core-language) or async runtime errors specifically.
SKILL.md
3.9 KB, as published. Nobody here has run it
Rust Error Handling
The consensus split: thiserror for libraries, anyhow for applications. A library
exposes a typed error its callers can match; an application wants one ergonomic error
type and rich context. Getting this boundary right is the whole discipline.
Agent Workflow (MANDATORY)
- fuse-ai-pilot:explore-codebase — is this crate a library (published API, other code depends on it) or a binary/application? That answer picks the tool.
- fuse-ai-pilot:research-expert — confirm current
thiserror/anyhowAPI before writing derives (verification chain: fuse-browser fast-path ondocs.rs/thiserroranddocs.rs/anyhow→ Context7 → Exa). - After writing, run fuse-ai-pilot:sniper and
cargo clippy.
The rule
| Crate kind | Tool | Why |
|---|---|---|
| Library (others depend on it) | thiserror | Typed enum, #[derive(Error)], callers can match on variants |
| Application (binary, top level) | anyhow | anyhow::Result<T>, ? everywhere, .context() for breadcrumbs |
| Simple / dep-free | hand-written std::error::Error | No dependency when one or two variants suffice |
Critical Rules
- Never expose
anyhow::Errorin a library's public API. It erases the type, so callers cannot match or handle specific failures. Return a typedenumerror. thiserror is designed to not appear in your public API — switching to/from a hand-written impl is not a breaking change. - Applications use
anyhow; libraries usethiserror. Do not pullanyhowinto a reusable library's signatures. - Add context at each layer in application code:
.context("...")/.with_context(|| ...)turns "No such file or directory" into a traceable chain. #[from]for zero-boilerplate conversion, so?lifts a source error into your enum.#[from]implies#[source]— never write both.- Errors are values; panics are bugs. Use
Resultfor anything a caller could reasonably recover from. Reservepanic!/unwrap/expectfor broken invariants.
Reference Guide
Concepts
| Topic | Reference | Load when |
|---|---|---|
| thiserror (libraries) | thiserror-libraries.md | Building a typed error enum for a library API |
| anyhow (applications) | anyhow-applications.md | Handling errors in a binary / top-level app |
| Error design | error-design.md | Shaping enums, #[from] conversion, recoverable vs panic, the anyhow/thiserror boundary |
Templates
| Template | Load when |
|---|---|
| library-error.md | Need a complete thiserror library error module |
| application-error.md | Need a complete anyhow application entry point with context |
Validation Checklist
- Library errors are a typed
enumderivingthiserror::Error— noanyhowin the public API - Application code returns
anyhow::Result<T>and adds.context(...) -
#[from]used for source conversions; no redundant#[source]alongside it -
?used instead ofunwrap()on fallible values - Panics only guard genuine invariants, with a reason
-
cargo clippyclean, sniper passed