skillby MacroMan5

error-handling-completeness

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.

Installs: 0
Used in: 1 repos
Updated: 2d ago
$npx ai-builder add skill MacroMan5/error-handling-completeness

Installs to .claude/skills/error-handling-completeness/

# 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?

```python
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)
```python
# ❌ 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**
```python
# ❌ 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**
```python
# ❌ 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**
```python
# ❌ 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)
```javascript
// ❌ 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
```python
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
```python
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
```python
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

```markdown
## 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

```bash
# 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

Quick Install

$npx ai-builder add skill MacroMan5/error-handling-completeness

Details

Type
skill
Author
MacroMan5
Slug
MacroMan5/error-handling-completeness
Created
6d ago