rust-error-handling

SkillAI & models

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).

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the rust-error-handling skill

What this skill tells your AI

The instructions your AI receives, as published by fusengine/agents in plugins/rust-expert/skills/rust-error-handling/SKILL.md and read by ahel’s review.

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.

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 kindToolWhy
Library (others depend on it)thiserrorTyped enum, #[derive(Error)], callers can match on variants
Application (binary, top level)anyhowanyhow::Result<T>, ? everywhere, .context() for breadcrumbs
Simple / dep-freehand-written std::error::ErrorNo 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

TopicReferenceLoad when
thiserror (libraries)thiserror-libraries.mdBuilding a typed error enum for a library API
anyhow (applications)anyhow-applications.mdHandling errors in a binary / top-level app
Error designerror-design.mdShaping enums, #[from] conversion, recoverable vs panic, the anyhow/thiserror boundary

Templates

TemplateLoad when
library-error.mdNeed a complete thiserror library error module
application-error.mdNeed 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

Signals

GitHub stars
25
Forks
4
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
rust-error-handling-fusengine
Source
github.com/fusengine/agents