Agent Skills: Rust Error Handling

Use when designing Rust error handling — thiserror vs anyhow, typed error enums, #[from] conversions, or recoverable errors vs panics. Not for ownership/borrowing (rust-core-language).

UncategorizedID: fusengine/agents/rust-error-handling

Install this agent skill to your local

pnpm dlx add-skill https://github.com/Fusengine/claude-plugins/tree/HEAD/plugins/rust-expert/skills/rust-error-handling

Skill Files

Browse the full folder contents for rust-error-handling.

Download Skill

Loading file tree…

plugins/rust-expert/skills/rust-error-handling/SKILL.md

Skill Metadata

Name
rust-error-handling
Description
Use when designing Rust error handling — thiserror vs anyhow, typed error enums, #[from] conversions, or recoverable errors vs panics. Not for ownership/borrowing (rust-core-language).
<objective> This skill covers the thiserror-for-libraries, anyhow-for-applications split in Rust: building typed error enums with #[derive(Error)] for library APIs callers can match on, using anyhow::Result with .context()/.with_context() in application code, and zero-boilerplate error conversion via #[from].

It also covers the recoverable-errors-vs-panics decision — Result for anything a caller could reasonably recover from, panic!/unwrap/expect reserved for broken invariants — and the rule that anyhow::Error must never leak into a library's public API.

Out of scope: general ownership/borrowing design belongs to rust-core-language; async-runtime-specific error handling is not covered here. </objective>

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)

  1. 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.
  2. fuse-ai-pilot:research-expert — confirm current thiserror / anyhow API before writing derives (verification chain: fuse-browser fast-path on docs.rs/thiserror and docs.rs/anyhow → Context7 → Exa).
  3. 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

  1. Never expose anyhow::Error in a library's public API. It erases the type, so callers cannot match or handle specific failures. Return a typed enum error. thiserror is designed to not appear in your public API — switching to/from a hand-written impl is not a breaking change.
  2. Applications use anyhow; libraries use thiserror. Do not pull anyhow into a reusable library's signatures.
  3. Add context at each layer in application code: .context("...") / .with_context(|| ...) turns "No such file or directory" into a traceable chain.
  4. #[from] for zero-boilerplate conversion, so ? lifts a source error into your enum. #[from] implies #[source] — never write both.
  5. Errors are values; panics are bugs. Use Result for anything a caller could reasonably recover from. Reserve panic!/unwrap/expect for 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 enum deriving thiserror::Error — no anyhow in the public API
  • [ ] Application code returns anyhow::Result<T> and adds .context(...)
  • [ ] #[from] used for source conversions; no redundant #[source] alongside it
  • [ ] ? used instead of unwrap() on fallible values
  • [ ] Panics only guard genuine invariants, with a reason
  • [ ] cargo clippy clean, sniper passed