Claude Code Plugins

Community-maintained marketplace

Feedback

error-handling-completeness

@MacroMan5/claude-code-workflow-plugins
1
0

Evaluates if error handling is sufficient for new code - checks try-catch coverage, logging, user messages, retry logic. Focuses on external calls and user-facing code.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name error-handling-completeness
description Evaluates if error handling is sufficient for new code - checks try-catch coverage, logging, user messages, retry logic. Focuses on external calls and user-facing code.

Error Handling Completeness Skill

Purpose: Prevent production crashes with systematic error handling.

Trigger Words: API call, external, integration, network, database, file, user input, async, promise, await


Quick Decision: Needs Error Handling Check?

def needs_error_check(code_context: dict) -> bool:
    """Decide if error handling review is needed."""

    # High-risk operations (always check)
    high_risk = [
        "fetch", "axios", "requests", "http",  # HTTP calls
        "db.", "query", "execute",  # Database
        "open(", "read", "write",  # File I/O
        "json.loads", "json.parse",  # JSON parsing
        "int(", "float(",  # Type conversions
        "subprocess", "exec",  # External processes
        "await", "async",  # Async operations
    ]

    code = code_context.get("code", "").lower()
    return any(risk in code for risk in high_risk)

Error Handling Checklist (Fast)

1. External API Calls (Most Critical)

# ❌ BAD - No error handling
def get_user_data(user_id):
    response = requests.get(f"https://api.example.com/users/{user_id}")
    return response.json()  # What if network fails? 404? Timeout?

# ✅ GOOD - Complete error handling
def get_user_data(user_id):
    try:
        response = requests.get(
            f"https://api.example.com/users/{user_id}",
            timeout=5  # Timeout!
        )
        response.raise_for_status()  # Check HTTP errors
        return response.json()

    except requests.Timeout:
        logger.error(f"Timeout fetching user {user_id}")
        raise ServiceUnavailableError("User service timeout")

    except requests.HTTPError as e:
        if e.response.status_code == 404:
            raise UserNotFoundError(f"User {user_id} not found")
        logger.error(f"HTTP error fetching user: {e}")
        raise

    except requests.RequestException as e:
        logger.error(f"Network error: {e}")
        raise ServiceUnavailableError("Cannot reach user service")

Quick Checks:

  • ✅ Timeout set?
  • ✅ HTTP errors handled?
  • ✅ Network errors caught?
  • ✅ Logged?
  • ✅ User-friendly error returned?

2. Database Operations

# ❌ BAD - Swallows errors
def delete_user(user_id):
    try:
        db.execute("DELETE FROM users WHERE id = ?", [user_id])
    except Exception:
        pass  # Silent failure!

# ✅ GOOD - Specific handling
def delete_user(user_id):
    try:
        result = db.execute("DELETE FROM users WHERE id = ?", [user_id])
        if result.rowcount == 0:
            raise UserNotFoundError(f"User {user_id} not found")

    except db.IntegrityError as e:
        logger.error(f"Cannot delete user {user_id}: {e}")
        raise DependencyError("User has related records")

    except db.OperationalError as e:
        logger.error(f"Database error: {e}")
        raise DatabaseUnavailableError()

Quick Checks:

  • ✅ Specific exceptions (not bare except)?
  • ✅ Logged?
  • ✅ User-friendly error?

3. File Operations

# ❌ BAD - File might not exist
def read_config():
    with open("config.json") as f:
        return json.load(f)

# ✅ GOOD - Handle missing file
def read_config():
    try:
        with open("config.json") as f:
            return json.load(f)
    except FileNotFoundError:
        logger.warning("config.json not found, using defaults")
        return DEFAULT_CONFIG
    except json.JSONDecodeError as e:
        logger.error(f"Invalid JSON in config.json: {e}")
        raise ConfigurationError("Malformed config.json")
    except PermissionError:
        logger.error("Permission denied reading config.json")
        raise

Quick Checks:

  • ✅ FileNotFoundError handled?
  • ✅ JSON parse errors caught?
  • ✅ Permission errors handled?

4. Type Conversions

# ❌ BAD - Crash on invalid input
def process_age(age_str):
    age = int(age_str)  # What if "abc"?
    return age * 2

# ✅ GOOD - Validated
def process_age(age_str):
    try:
        age = int(age_str)
        if age < 0 or age > 150:
            raise ValueError("Age out of range")
        return age * 2
    except ValueError:
        raise ValidationError(f"Invalid age: {age_str}")

Quick Checks:

  • ✅ ValueError caught?
  • ✅ Range validation?
  • ✅ Clear error message?

5. Async/Await (JavaScript/Python)

// ❌ BAD - Unhandled promise rejection
async function fetchUser(id) {
    const user = await fetch(`/api/users/${id}`);
    return user.json();  // What if network fails?
}

// ✅ GOOD - Handled
async function fetchUser(id) {
    try {
        const response = await fetch(`/api/users/${id}`);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }
        return await response.json();
    } catch (error) {
        console.error(`Failed to fetch user ${id}:`, error);
        throw new ServiceError("Cannot fetch user");
    }
}

Quick Checks:

  • ✅ Try-catch around await?
  • ✅ HTTP status checked?
  • ✅ Logged?

Error Handling Patterns

Pattern 1: Retry with Exponential Backoff

def call_api_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.get(url, timeout=5)
            response.raise_for_status()
            return response.json()

        except requests.Timeout:
            if attempt < max_retries - 1:
                wait = 2 ** attempt  # 1s, 2s, 4s
                logger.warning(f"Timeout, retrying in {wait}s...")
                time.sleep(wait)
            else:
                raise

When to use: Transient failures (network, rate limits)


Pattern 2: Fallback Values

def get_user_avatar(user_id):
    try:
        return fetch_from_cdn(user_id)
    except CDNError:
        logger.warning(f"CDN failed for user {user_id}, using default")
        return DEFAULT_AVATAR_URL

When to use: Non-critical operations, graceful degradation


Pattern 3: Circuit Breaker

class CircuitBreaker:
    def __init__(self, max_failures=5):
        self.failures = 0
        self.max_failures = max_failures
        self.is_open = False

    def call(self, func):
        if self.is_open:
            raise ServiceUnavailableError("Circuit breaker open")

        try:
            result = func()
            self.failures = 0  # Reset on success
            return result
        except Exception as e:
            self.failures += 1
            if self.failures >= self.max_failures:
                self.is_open = True
                logger.error("Circuit breaker opened")
            raise

When to use: Preventing cascading failures


Output Format

## Error Handling Report

**Status**: [✅ COMPLETE | ⚠️ GAPS FOUND]

---

### Missing Error Handling: 3

1. **[HIGH] No timeout on API call (api_client.py:45)**
   - **Issue**: `requests.get()` has no timeout
   - **Risk**: Indefinite hang if service slow
   - **Fix**:
     ```python
     response = requests.get(url, timeout=5)
     ```

2. **[HIGH] Unhandled JSON parse error (config.py:12)**
   - **Issue**: `json.load()` not wrapped in try-catch
   - **Risk**: Crash on malformed JSON
   - **Fix**:
     ```python
     try:
         config = json.load(f)
     except json.JSONDecodeError as e:
         logger.error(f"Invalid JSON: {e}")
         return DEFAULT_CONFIG
     ```

3. **[MEDIUM] Silent exception swallowing (db.py:89)**
   - **Issue**: `except Exception: pass`
   - **Risk**: Failures go unnoticed
   - **Fix**: Log error or use specific exception

---

**Good Practices Found**: 2
- ✅ Database errors logged properly (db.py:34)
- ✅ Retry logic on payment API (payments.py:67)

---

**Next Steps**:
1. Add timeout to API calls (5 min)
2. Wrap JSON parsing in try-catch (2 min)
3. Remove silent exception handlers (3 min)

What This Skill Does NOT Do

❌ Catch every possible exception (too noisy) ❌ Force try-catch everywhere (only where needed) ❌ Replace integration tests ❌ Handle business logic errors (validation, etc.)

DOES: Check critical error-prone operations (network, I/O, parsing)


Configuration

# Strict mode: check all functions
export LAZYDEV_ERROR_HANDLING_STRICT=1

# Disable error handling checks
export LAZYDEV_DISABLE_ERROR_CHECKS=1

Version: 1.0.0 Focus: External calls, I/O, parsing, async Speed: <2 seconds per file