m06-error-handling
229
总安装量
226
周安装量
#1201
全站排名
安装命令
npx skills add https://github.com/zhanghandong/rust-skills --skill m06-error-handling
Agent 安装分布
opencode
184
codex
167
gemini-cli
158
github-copilot
145
amp
98
Skill 文档
Error Handling
Layer 1: Language Mechanics
Core Question
Is this failure expected or a bug?
Before choosing error handling strategy:
- Can this fail in normal operation?
- Who should handle this failure?
- What context does the caller need?
Error â Design Question
| Pattern | Don’t Just Say | Ask Instead |
|---|---|---|
| unwrap panics | “Use ?” | Is None/Err actually possible here? |
| Type mismatch on ? | “Use anyhow” | Are error types designed correctly? |
| Lost error context | “Add .context()” | What does the caller need to know? |
| Too many error variants | “Use Box” | Is error granularity right? |
Thinking Prompt
Before handling an error:
-
What kind of failure is this?
- Expected â Result<T, E>
- Absence normal â Option
- Bug/invariant â panic!
- Unrecoverable â panic!
-
Who handles this?
- Caller â propagate with ?
- Current function â match/if-let
- User â friendly error message
- Programmer â panic with message
-
What context is needed?
- Type of error â thiserror variants
- Call chain â anyhow::Context
- Debug info â anyhow or tracing
Trace Up â
When error strategy is unclear:
"Should I return Result or Option?"
â Ask: Is absence/failure normal or exceptional?
â Check: m09-domain (what does domain say?)
â Check: domain-* (error handling requirements)
| Situation | Trace To | Question |
|---|---|---|
| Too many unwraps | m09-domain | Is the data model right? |
| Error context design | m13-domain-error | What recovery is needed? |
| Library vs app errors | m11-ecosystem | Who are the consumers? |
Trace Down â
From design to implementation:
"Expected failure, library code"
â Use: thiserror for typed errors
"Expected failure, application code"
â Use: anyhow for ergonomic errors
"Absence is normal (find, get, lookup)"
â Use: Option<T>
"Bug or invariant violation"
â Use: panic!, assert!, unreachable!
"Need to propagate with context"
â Use: .context("what was happening")
Quick Reference
| Pattern | When | Example |
|---|---|---|
Result<T, E> |
Recoverable error | fn read() -> Result<String, io::Error> |
Option<T> |
Absence is normal | fn find() -> Option<&Item> |
? |
Propagate error | let data = file.read()?; |
unwrap() |
Dev/test only | config.get("key").unwrap() |
expect() |
Invariant holds | env.get("HOME").expect("HOME set") |
panic! |
Unrecoverable | panic!("critical failure") |
Library vs Application
| Context | Error Crate | Why |
|---|---|---|
| Library | thiserror |
Typed errors for consumers |
| Application | anyhow |
Ergonomic error handling |
| Mixed | Both | thiserror at boundaries, anyhow internally |
Decision Flowchart
Is failure expected?
ââ Yes â Is absence the only "failure"?
â ââ Yes â Option<T>
â ââ No â Result<T, E>
â ââ Library â thiserror
â ââ Application â anyhow
ââ No â Is it a bug?
ââ Yes â panic!, assert!
ââ No â Consider if really unrecoverable
Use ? â Need context?
ââ Yes â .context("message")
ââ No â Plain ?
Common Errors
| Error | Cause | Fix |
|---|---|---|
unwrap() panic |
Unhandled None/Err | Use ? or match |
| Type mismatch | Different error types | Use anyhow or From |
| Lost context | ? without context |
Add .context() |
cannot use ? |
Missing Result return | Return Result<(), E> |
Anti-Patterns
| Anti-Pattern | Why Bad | Better |
|---|---|---|
.unwrap() everywhere |
Panics in production | .expect("reason") or ? |
| Ignore errors silently | Bugs hidden | Handle or propagate |
panic! for expected errors |
Bad UX, no recovery | Result |
| Box everywhere | Lost type info | thiserror |
Related Skills
| When | See |
|---|---|
| Domain error strategy | m13-domain-error |
| Crate boundaries | m11-ecosystem |
| Type-safe errors | m05-type-driven |
| Mental models | m14-mental-model |