npx skills add https://www.modelscope.cn/collections/sonia2026/cuowuxiufu
smithery/huiali
rust-error
Error handling expert covering Result, Option, panic strategies, custom error types with thiserror/anyhow, error propagation patterns, and context-rich error chains.
Similar popular skills
Related neighbors and high-traction skills in the same topics — useful to compare before installing.
Guidance for distinctive, intentional visual design when building new UI or reshaping an existi…
866.4K installsBrowser automation CLI for AI agents. Use when the user needs to interact with websites, includ…
810.4K installsReview UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "chec…
617.3K installsBuild, deploy, evaluate, optimize, fine-tune, and manage Microsoft Foundry agents, models, and …
576.5K installsDebug Azure production issues on Azure using AppLens, Azure Monitor, resource health, and safe …
568.9K installsAlso in this package
Other skills from smithery/huiali · top by installs.
npx skills add smithery/huiali
More details
Agent compatibility
Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.
Also listed on
Alternate registries and mirrors of this skill.
Skill metadata
Parsed from SKILL.md frontmatter.
More metadata
- triggers
- ["Result","Error","panic","?","unwrap","expect","anyhow","thiserror","error handling","Option"]
Package contents
Files included with this skill beyond the listing page.
-
skill md
SKILL.md10,049 B -
docs
SUMMARY.md183 B
History
- First recorded snapshot · 0 installs
SKILL.md
Solution Patterns
Pattern 1: Option for Normal Absence
// Lookup operations where "not found" is normal
fn find_user(id: u32) -> Option<User> {
users.get(&id)
}
// Usage patterns
match find_user(123) {
Some(user) => println!("Found: {}", user.name),
None => println!("User not found"),
}
// Or convert to Result for propagation
let user = find_user(123).ok_or(UserNotFoundError)?;
When to use: Queries, lookups, optional configuration values.
Key insight: None carries no information, just absence.
Pattern 2: Result for Expected Failures
// File might not exist (expected failure)
fn read_config(path: &Path) -> Result<String, io::Error> {
std::fs::read_to_string(path)
}
// Network request might timeout
fn fetch(url: &str) -> Result<Response, reqwest::Error> {
reqwest::blocking::get(url)
}
When to use: I/O operations, parsing, validation, network calls.
Key insight: Error type carries information about why it failed.
Pattern 3: Custom Error Types (thiserror)
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParseError {
#[error("invalid format: {0}")]
InvalidFormat(String),
#[error("missing required field: {0}")]
MissingField(&'static str),
#[error("IO error")]
Io(#[from] io::Error),
#[error("parse error: {0}")]
Parse(#[from] serde_json::Error),
}
// Use in library code
pub fn parse_config(input: &str) -> Result<Config, ParseError> {
let raw: RawConfig = serde_json::from_str(input)?; // Auto-converts
validate_config(raw)
}
When to use: Library code, public APIs, need type-safe error handling.
Trade-offs: More boilerplate, but precise error types.
Pattern 4: Flexible Errors (anyhow)
use anyhow::{Context, Result, bail};
fn process_request() -> Result<Response> {
let config = std::fs::read_to_string("config.json")
.context("failed to read config file")?;
let parsed: Config = serde_json::from_str(&config)
.context("failed to parse config as JSON")?;
if !parsed.is_valid() {
bail!("invalid configuration: missing API key");
}
Ok(build_response(parsed))
}
When to use: Application code, rapid development, error context matters more than types.
Trade-offs: Loses type information, but gains flexibility and context.
Workflow
Step 1: Classify the Failure
Is absence normal?
→ Option<T>
Is failure expected and recoverable?
→ Result<T, E>
Is this a bug or invariant violation?
→ panic!() or assert!()
Step 2: Choose Error Representation
Library code (public API)?
→ thiserror (typed errors)
Application code (internal)?
→ anyhow (flexible errors)
Need error conversions?
→ Implement From traits
Step 3: Propagate or Handle
Can caller handle this?
→ Return Result, use ?
Need to add context?
→ .context("why it failed")?
Must handle here?
→ match / if let / unwrap_or
Error Propagation Best Practices
✅ Good Patterns
// Clear error types
fn validate() -> Result<(), ValidationError> {
if name.is_empty() {
return Err(ValidationError::EmptyName);
}
Ok(())
}
// Add context during propagation
let config = File::open("config.json")
.context("failed to open config.json")?;
// Use ? operator
let data = read_file(&path)?;
// Provide defaults
let timeout = config.timeout.unwrap_or(Duration::from_secs(30));
// Pattern match for complex handling
match parse_input(input) {
Ok(value) => process(value),
Err(ParseError::InvalidFormat(msg)) => log_and_retry(msg),
Err(e) => return Err(e),
}
❌ Anti-Patterns
// ❌ unwrap() on operations that can fail
let content = std::fs::read_to_string("config.json").unwrap();
// ❌ Silently ignore errors
let _ = some_fallible_operation();
// ❌ Generic error messages
Err(anyhow!("error")) // Too vague
// ❌ Converting all errors to strings
.map_err(|e| e.to_string())? // Loses type info
// ❌ Panic for expected failures
let num: i32 = input.parse().expect("parse failed"); // User input!
When to Panic
✅ Acceptable Panic Scenarios
| Scenario | Example | Reasoning |
|---|---|---|
| Invariant violation | Array index out of bounds | Programming bug |
| Initialization checks | env::var("HOME").expect(...) |
Required for program to run |
| Test assertions | assert_eq!(result, expected) |
Verify assumptions |
| Unrecoverable state | OOM, corrupted data structures | Can't continue safely |
// ✅ Acceptable: initialization check
let api_key = std::env::var("API_KEY")
.expect("API_KEY environment variable must be set");
// ✅ Acceptable: test assertion
#[test]
fn test_user_creation() {
let user = create_user("Alice");
assert_eq!(user.name, "Alice");
}
// ✅ Acceptable: invariant violation
let first = queue.pop().expect("queue should never be empty at this point");
❌ Unacceptable Panic Scenarios
// ❌ User input validation
let num: i32 = input.parse().unwrap(); // Use Result instead
// ❌ Network operations
let response = reqwest::blocking::get(url).unwrap(); // Use Result
// ❌ File operations
let config = std::fs::read_to_string("config.json").unwrap(); // Use Result
Error Type Design
Enum for Multiple Error Cases
#[derive(Error, Debug)]
pub enum ConfigError {
#[error("file not found at {path}")]
FileNotFound { path: String },
#[error("invalid syntax at line {line}: {message}")]
InvalidSyntax { line: usize, message: String },
#[error("missing required field: {0}")]
MissingField(String),
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Parse(#[from] serde_json::Error),
}
Nested Errors with Context
#[derive(Error, Debug)]
pub enum AppError {
#[error("configuration error")]
Config(#[from] ConfigError),
#[error("database error")]
Database(#[from] DatabaseError),
#[error("authentication failed: {0}")]
Auth(String),
}
Common Pitfalls
| Anti-Pattern | Problem | Correct Approach |
|---|---|---|
.unwrap() everywhere |
Production panics | Use ? or .with_context() |
Box<dyn Error> |
Loses type information | Use thiserror enums |
| Silent error ignoring | Bugs go unnoticed | Handle or propagate |
| Deep error hierarchies | Over-engineering | Design as needed |
| Panic for control flow | Abusing panic | Use normal control flow |
| String errors | No pattern matching | Use typed errors |
Quick Reference
| Scenario | Choice | Tool |
|---|---|---|
| Library returns custom errors | Result<T, CustomEnum> |
thiserror |
| Application rapid development | Result<T, anyhow::Error> |
anyhow |
| Absence is normal | Option<T> |
None / Some(x) |
| Intentional panic | panic!() / assert!() |
Special cases only |
| Error conversion | .map_err() / .context() |
Add context |
| Fallback values | .unwrapor() / .unwrapor_else() |
Safe defaults |
| Early return | ? operator |
Propagate errors |
Review Checklist
When reviewing error handling code:
- All fallible operations return
ResultorOption - Error types are meaningful (not just
String) - Error context is preserved through propagation
-
unwrap()used only with justification (comments) -
panic!()used only for bugs or unrecoverable states - Library code uses typed errors (thiserror)
- Application code adds context (anyhow
.context()) - Error messages are actionable for users/operators
- No silent error swallowing (
let _ = ...) - Tests cover error paths, not just happy paths
Verification Commands
# Check for unwrap/expect usage
cargo clippy -- -W clippy::unwrap_used -W clippy::expect_used
# Check for panic in production code
cargo clippy -- -W clippy::panic
# Run tests including error paths
cargo test
# Check for unused Results
cargo clippy -- -D unused_must_use
# Verify error types implement Error trait
cargo check
Conversion Patterns
Option ↔ Result
// Option → Result
let result: Result<T, E> = option.ok_or(error_value)?;
let result: Result<T, E> = option.ok_or_else(|| compute_error())?;
// Result → Option
let option: Option<T> = result.ok();
// Result<Option<T>, E> → Result<T, E>
result.and_then(|opt| opt.ok_or(error))?;
Error Type Conversions
// Manual conversion
.map_err(|e| MyError::from(e))?;
// Automatic with #[from]
// Requires: #[derive(Error, Debug)] with #[from] attribute
result?; // Auto-converts if From impl exists
// Add context
.map_err(|e| MyError::Wrapped(e.to_string()))?;
// Use anyhow for flexibility
.context("operation failed")?;
Advanced: Error Source Chains
use std::error::Error;
fn print_error_chain(e: &dyn Error) {
eprintln!("Error: {}", e);
let mut source = e.source();
while let Some(e) = source {
eprintln!(" Caused by: {}", e);
source = e.source();
}
}
// Usage
if let Err(e) = dangerous_operation() {
print_error_chain(&e);
}
Related Skills
- rust-error-advanced - Advanced error patterns (thiserror, anyhow, error chains)
- rust-anti-pattern - Error handling anti-patterns to avoid
- rust-coding - Error handling coding standards
- rust-web - Error handling in web contexts
- rust-async - Error handling in async code
Localized Reference
- Chinese version: [SKILLZH.md](./SKILLZH.md) - 完整中文版本,包含所有内容