Claude-skill-registry 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.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/error-handling-completeness" ~/.claude/skills/majiayu000-claude-skill-registry-error-handling-completeness && rm -rf "$T"
skills/data/error-handling-completeness/SKILL.mdError 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