All tools
SkillCurated · reviewed

Error-Handling Audit Skill

Updated Jul 7, 2026

A Claude Code skill that scans code for inadequate error handling: swallowed exceptions, empty catch blocks, silent fallbacks that hide failures, and catch-all handlers that lose error type and context. Each finding proposes a concrete, targeted fix.

What it does

  • /audit-errors

    Scan code for swallowed errors, empty catch blocks, silent fallbacks, and catch-all handlers.

  • /audit-errors <file>

    Audit a specific file or function for error-handling problems and propose targeted fixes.

Files (1)

SKILL.mdprimary · markdown · 4.3 KB
# Error-Handling Audit Skill

---
slug: error-handling-audit-skill
version: 1.0.0
category: engineering
command: /audit-errors
---

## What it does
Scans a function, file, or module for inadequate error handling and proposes fixes.
Targets the most dangerous patterns: empty catch blocks, swallowed rejections,
silent fallbacks that return null/undefined on failure, and generic catch-all handlers
that erase the error type and its context.

## Trigger
Use this skill when asked to audit, review, or improve error handling.
Typical invocations:
- "Audit this file for swallowed errors"
- "Why is this function silently failing?"
- `/audit-errors` in Claude Code
- `/audit-errors <file>` to target a specific file or function

## Input
Provide one or more of:
1. The code to audit (pasted or referenced by file path)
2. The language and runtime (TypeScript/Node, Python, Go, etc.)
3. The error-handling conventions in use (custom error classes, Result types, structured logging)
4. Known failure modes you want to check specifically

## Method

Scan for these patterns, in descending severity:

### Critical
- **Empty catch block** — `catch (e) {}` or `except: pass` — error is swallowed completely.
- **Unhandled promise rejection** — `someAsync()` called without `await` or `.catch()`, or a
  `Promise.all` where one rejection silently voids the rest.
- **Ignored return value carrying an error** — Go-style `val, _ := fn()` where `_` discards an error.

### High
- **Silent null/undefined fallback** — `catch (e) { return null; }` where the caller cannot
  distinguish "not found" from "error".
- **Catch-all that loses type** — `catch (e: unknown) { console.log(e); }` without re-throw,
  error class check, or structured logging.
- **async function that never rejects or resolves** — dangling promise from a missing `return`.

### Medium
- **Error logged but not surfaced** — the error is logged but the function returns a success
  value, misleading the caller.
- **Stack trace discarded** — `throw new Error(e.message)` re-wraps without `{ cause: e }`,
  losing the original stack.
- **Overly broad catch** — catches `Error` when only `NetworkError` is expected; hides programming errors.

### Low
- **Inconsistent error shape** — some paths throw, others return `{ error: string }`; callers must handle both.
- **Missing finally** — resource (file handle, DB connection, lock) not released on error path.

## Output format

Produce a findings list sorted by severity, then a **Summary** table.
For each finding, show the problematic code snippet and the proposed fix side by side.

```
## Findings

[Critical] Empty catch block swallows all errors from fetchUser()
  File: src/api/user.ts, line 24
  Before: catch (e) {}
  After:  catch (e) { logger.error('fetchUser failed', { userId, error: e }); throw e; }

## Summary
| Severity | Count |
|----------|-------|
| Critical | N     |
| High     | N     |
| Medium   | N     |
| Low      | N     |
```

## Example output

```
## Findings

[Critical] Unhandled promise rejection in background sync (src/sync.ts:41)
  Before: sync().catch(() => {})
  After:  sync().catch((e) => logger.error('Background sync failed', { error: e }));
  Why: Silently ignoring a sync failure means data loss goes undetected.

[High] fetchConfig returns null on error, caller cannot distinguish missing vs. broken (src/config.ts:18)
  Before: catch (e) { return null; }
  After:  catch (e) { throw new ConfigFetchError('Failed to load remote config', { cause: e }); }
  Why: The caller does null checks that will silently use stale config when the fetch errors.

[Medium] Error re-thrown without cause, original stack is lost (src/db.ts:55)
  Before: throw new Error(e.message)
  After:  throw new DatabaseError('Query failed', { cause: e })
  Why: Node's native error chaining (cause) preserves the original stack in logs and monitoring tools.

[Low] DB connection not closed in error path — missing finally (src/db.ts:72)
  Fix: Wrap the query block in try/finally and call conn.release() in the finally block.

## Summary
| Severity | Count |
|----------|-------|
| Critical | 1     |
| High     | 1     |
| Medium   | 1     |
| Low      | 1     |
```

## Commands (Claude Code)

- `/audit-errors` — Scan the selected or pasted code for error-handling problems and propose fixes.
- `/audit-errors <file>` — Audit a specific file or function by name or pasted content.