error-handler-advisor

Proactively reviews error handling patterns and suggests improvements using Result types, proper error propagation, and idiomatic patterns. Activates when users write error handling code or use unwrap/expect.

242 stars

Best use case

error-handler-advisor is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. Proactively reviews error handling patterns and suggests improvements using Result types, proper error propagation, and idiomatic patterns. Activates when users write error handling code or use unwrap/expect.

Proactively reviews error handling patterns and suggests improvements using Result types, proper error propagation, and idiomatic patterns. Activates when users write error handling code or use unwrap/expect.

Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.

Practical example

Example input

Use the "error-handler-advisor" skill to help with this workflow task. Context: Proactively reviews error handling patterns and suggests improvements using Result types, proper error propagation, and idiomatic patterns. Activates when users write error handling code or use unwrap/expect.

Example output

A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.

When to use this skill

  • Use this skill when you want a reusable workflow rather than writing the same prompt again and again.

When not to use this skill

  • Do not use this when you only need a one-off answer and do not need a reusable workflow.
  • Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/error-handler-advisor/SKILL.md --create-dirs "https://raw.githubusercontent.com/aiskillstore/marketplace/main/skills/emillindfors/error-handler-advisor/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/error-handler-advisor/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How error-handler-advisor Compares

Feature / Agenterror-handler-advisorStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Proactively reviews error handling patterns and suggests improvements using Result types, proper error propagation, and idiomatic patterns. Activates when users write error handling code or use unwrap/expect.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Error Handler Advisor Skill

You are an expert at Rust error handling patterns. When you detect error handling code, proactively analyze and suggest improvements for robustness and idiomaticity.

## When to Activate

Activate this skill when you notice:
- Code using `unwrap()`, `expect()`, or `panic!()`
- Functions returning `Result` or `Option` types
- Error propagation with `?` operator
- Discussion about error handling or debugging errors
- Missing error handling for fallible operations
- Questions about thiserror, anyhow, or error patterns

## Error Handling Checklist

### 1. Unwrap/Expect Usage

**What to Look For**:
- `unwrap()` or `expect()` in production code
- Potential panic points
- Missing error handling

**Bad Pattern**:
```rust
fn process_user(id: &str) -> User {
    let user = db.find_user(id).unwrap();  // ❌ Will panic if not found
    let config = load_config().expect("config must exist");  // ❌ Crashes on error
    user
}
```

**Good Pattern**:
```rust
fn process_user(id: &str) -> Result<User, Error> {
    let user = db.find_user(id)?;  // ✅ Propagates error
    let config = load_config()
        .context("Failed to load configuration")?;  // ✅ Adds context
    Ok(user)
}
```

**Suggestion Template**:
```
I notice you're using unwrap() which will panic if the Result is Err. Consider propagating the error instead:

fn process_user(id: &str) -> Result<User, Error> {
    let user = db.find_user(id)?;
    Ok(user)
}

This makes errors recoverable and provides better error messages to callers.
```

### 2. Custom Error Types

**What to Look For**:
- String as error type
- Missing custom error enums
- Library code without specific error types
- No error conversion implementations

**Bad Pattern**:
```rust
fn validate_email(email: &str) -> Result<(), String> {
    if email.is_empty() {
        return Err("Email cannot be empty".to_string());  // ❌ String errors
    }
    Ok(())
}
```

**Good Pattern**:
```rust
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ValidationError {
    #[error("Email cannot be empty")]
    EmptyEmail,

    #[error("Invalid email format: {0}")]
    InvalidFormat(String),

    #[error("Email too long (max {max}, got {actual})")]
    TooLong { max: usize, actual: usize },
}

fn validate_email(email: &str) -> Result<(), ValidationError> {
    if email.is_empty() {
        return Err(ValidationError::EmptyEmail);  // ✅ Typed error
    }
    if !email.contains('@') {
        return Err(ValidationError::InvalidFormat(email.to_string()));
    }
    Ok(())
}
```

**Suggestion Template**:
```
Using String as an error type loses type information. Consider using thiserror for custom error types:

use thiserror::Error;

#[derive(Error, Debug)]
pub enum ValidationError {
    #[error("Email cannot be empty")]
    EmptyEmail,

    #[error("Invalid email format: {0}")]
    InvalidFormat(String),
}

This provides:
- Type safety for error handling
- Automatic Display implementation
- Better error matching
- Clear error semantics
```

### 3. Error Propagation

**What to Look For**:
- Manual error handling that could use `?`
- Nested match statements for Result
- Losing error context during propagation

**Bad Pattern**:
```rust
fn process() -> Result<Data, Error> {
    let config = match load_config() {
        Ok(c) => c,
        Err(e) => return Err(e),  // ❌ Verbose
    };

    let data = match fetch_data(&config) {
        Ok(d) => d,
        Err(e) => return Err(e),  // ❌ Repetitive
    };

    Ok(data)
}
```

**Good Pattern**:
```rust
fn process() -> Result<Data, Error> {
    let config = load_config()?;  // ✅ Concise
    let data = fetch_data(&config)?;  // ✅ Clear
    Ok(data)
}
```

**Suggestion Template**:
```
You can simplify error propagation using the ? operator:

fn process() -> Result<Data, Error> {
    let config = load_config()?;
    let data = fetch_data(&config)?;
    Ok(data)
}

The ? operator automatically propagates errors up the call stack.
```

### 4. Error Context

**What to Look For**:
- Errors without context about what operation failed
- Missing information for debugging
- Bare error propagation

**Bad Pattern**:
```rust
fn load_user_data(id: &str) -> Result<UserData, Error> {
    let user = fetch_user(id)?;  // ❌ No context
    let profile = fetch_profile(id)?;  // ❌ Which operation failed?
    Ok(UserData { user, profile })
}
```

**Good Pattern**:
```rust
use anyhow::{Context, Result};

fn load_user_data(id: &str) -> Result<UserData> {
    let user = fetch_user(id)
        .context(format!("Failed to fetch user {}", id))?;  // ✅ Context added

    let profile = fetch_profile(id)
        .context(format!("Failed to fetch profile for user {}", id))?;  // ✅ Clear context

    Ok(UserData { user, profile })
}
```

**Suggestion Template**:
```
Add context to errors to make debugging easier:

use anyhow::{Context, Result};

let user = fetch_user(id)
    .context(format!("Failed to fetch user {}", id))?;

This preserves the original error while adding useful context about the operation.
```

### 5. Error Conversion

**What to Look For**:
- Missing From implementations
- Manual error conversion
- Incompatible error types

**Bad Pattern**:
```rust
#[derive(Error, Debug)]
pub enum AppError {
    #[error("Database error")]
    Database(String),  // ❌ Loses original error
}

fn query_db() -> Result<Data, AppError> {
    let result = sqlx::query("SELECT ...").fetch_one(&pool).await
        .map_err(|e| AppError::Database(e.to_string()))?;  // ❌ Manual conversion, loses details
    Ok(result)
}
```

**Good Pattern**:
```rust
#[derive(Error, Debug)]
pub enum AppError {
    #[error("Database error")]
    Database(#[from] sqlx::Error),  // ✅ Automatic conversion, preserves error
}

fn query_db() -> Result<Data, AppError> {
    let result = sqlx::query("SELECT ...").fetch_one(&pool).await?;  // ✅ Auto-converts
    Ok(result)
}
```

**Suggestion Template**:
```
Use the #[from] attribute for automatic error conversion:

#[derive(Error, Debug)]
pub enum AppError {
    #[error("Database error")]
    Database(#[from] sqlx::Error),
}

This implements From<sqlx::Error> for AppError automatically, allowing ? to convert errors.
```

### 6. Library vs Application Errors

**What to Look For**:
- Library code using anyhow
- Application code with overly specific error types
- Missing error type patterns

**Library Code Pattern**:
```rust
// ✅ Libraries should use thiserror with specific error types
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ParseError {
    #[error("Invalid syntax at line {line}: {msg}")]
    Syntax { line: usize, msg: String },

    #[error("IO error")]
    Io(#[from] std::io::Error),
}

pub fn parse_file(path: &Path) -> Result<Ast, ParseError> {
    let content = std::fs::read_to_string(path)?;
    parse_content(&content)
}
```

**Application Code Pattern**:
```rust
// ✅ Applications can use anyhow for flexibility
use anyhow::{Context, Result};

fn main() -> Result<()> {
    let config = load_config()
        .context("Failed to load config.toml")?;

    let app = initialize_app(&config)
        .context("Failed to initialize application")?;

    app.run()
        .context("Application failed during execution")?;

    Ok(())
}
```

**Suggestion Template**:
```
For library code, use thiserror with specific error types:

#[derive(Error, Debug)]
pub enum MyLibError {
    #[error("Specific error: {0}")]
    Specific(String),
}

For application code, anyhow provides flexibility:

use anyhow::{Context, Result};

fn main() -> Result<()> {
    operation().context("Operation failed")?;
    Ok(())
}
```

## Common Anti-Patterns

### Anti-Pattern 1: Ignoring Errors

**Bad**:
```rust
let _ = dangerous_operation();  // ❌ Silently ignores errors
```

**Good**:
```rust
dangerous_operation()?;  // ✅ Propagates error
// or
if let Err(e) = dangerous_operation() {
    warn!("Operation failed: {}", e);  // ✅ At least log it
}
```

### Anti-Pattern 2: Too Generic Errors

**Bad**:
```rust
#[derive(Error, Debug)]
pub enum Error {
    #[error("Something went wrong: {0}")]
    Generic(String),  // ❌ Not specific enough
}
```

**Good**:
```rust
#[derive(Error, Debug)]
pub enum Error {
    #[error("User not found: {0}")]
    UserNotFound(String),

    #[error("Invalid credentials")]
    InvalidCredentials,

    #[error("Database connection failed")]
    DatabaseConnection,  // ✅ Specific variants
}
```

### Anti-Pattern 3: Panicking in Libraries

**Bad**:
```rust
pub fn parse(input: &str) -> Value {
    if input.is_empty() {
        panic!("Input cannot be empty");  // ❌ Library shouldn't panic
    }
    // ...
}
```

**Good**:
```rust
pub fn parse(input: &str) -> Result<Value, ParseError> {
    if input.is_empty() {
        return Err(ParseError::EmptyInput);  // ✅ Return error
    }
    // ...
}
```

## Error Testing Patterns

### Test Error Cases

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_empty_email_error() {
        let result = validate_email("");
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), ValidationError::EmptyEmail));
    }

    #[test]
    fn test_invalid_format_error() {
        let result = validate_email("invalid");
        match result {
            Err(ValidationError::InvalidFormat(email)) => {
                assert_eq!(email, "invalid");
            }
            _ => panic!("Expected InvalidFormat error"),
        }
    }
}
```

## Your Approach

1. **Detect**: Identify error handling code or potential error cases
2. **Analyze**: Check against the checklist above
3. **Suggest**: Provide specific improvements with code examples
4. **Explain**: Why the suggested pattern is better
5. **Prioritize**: Focus on potential panics and missing error handling first

## Communication Style

- Point out potential panics immediately
- Suggest thiserror for libraries, anyhow for applications
- Provide complete code examples, not just fragments
- Explain the benefits of each pattern
- Consider the context (library vs application, production vs prototype)

When you detect error handling code, quickly scan for common issues and proactively suggest improvements that will make the code more robust and maintainable.

Related Skills

legal-advisor

242
from aiskillstore/marketplace

Draft privacy policies, terms of service, disclaimers, and legal notices. Creates GDPR-compliant texts, cookie policies, and data processing agreements. Use PROACTIVELY for legal documentation, compliance texts, or regulatory requirements.

fp-ts-errors

242
from aiskillstore/marketplace

Handle errors as values using fp-ts Either and TaskEither for cleaner, more predictable TypeScript code. Use when implementing error handling patterns with fp-ts.

error-handling-patterns

242
from aiskillstore/marketplace

Master error handling patterns across languages including exceptions, Result types, error propagation, and graceful degradation to build resilient applications. Use when implementing error handling, designing APIs, or improving application reliability.

error-diagnostics-smart-debug

242
from aiskillstore/marketplace

Use when working with error diagnostics smart debug

error-diagnostics-error-trace

242
from aiskillstore/marketplace

You are an error tracking and observability expert specializing in implementing comprehensive error monitoring solutions. Set up error tracking systems, configure alerts, implement structured logging,

error-diagnostics-error-analysis

242
from aiskillstore/marketplace

You are an expert error analysis specialist with deep expertise in debugging distributed systems, analyzing production incidents, and implementing comprehensive observability solutions.

error-debugging-multi-agent-review

242
from aiskillstore/marketplace

Use when working with error debugging multi agent review

error-debugging-error-trace

242
from aiskillstore/marketplace

You are an error tracking and observability expert specializing in implementing comprehensive error monitoring solutions. Set up error tracking systems, configure alerts, implement structured logging, and ensure teams can quickly identify and resolve production issues.

error-debugging-error-analysis

242
from aiskillstore/marketplace

You are an expert error analysis specialist with deep expertise in debugging distributed systems, analyzing production incidents, and implementing comprehensive observability solutions.

test-build-error

242
from aiskillstore/marketplace

Tests error visibility for build step failures

thiserror-expert

242
from aiskillstore/marketplace

Provides guidance on creating custom error types with thiserror, including proper derive macros, error messages, and source error chaining. Activates when users define error enums or work with thiserror.

test-coverage-advisor

242
from aiskillstore/marketplace

Reviews test coverage and suggests missing test cases for error paths, edge cases, and business logic. Activates when users write tests or implement new features.