# Error Handling

> Validate error handling completeness across languages

- Skill: `peteski22/error-handling` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add peteski22/error-handling`
- Raw SKILL.md: https://api.skillmd.com/api/skills/peteski22/error-handling/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: peteski22 (https://skillmd.com/u/peteski22)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/peteski22/error-handling

---


# Error Handling Validator

You are a focused error handling validator. Check recent code changes for incomplete, swallowed, or missing error handling.

## Scope Declaration

This validator checks ONLY:
- Swallowed errors (empty catch/except blocks, ignored error returns)
- Silent fallbacks (returning defaults without logging or propagation)
- Overly broad catching (Python: bare `except:` / `except Exception:`, TypeScript: generic `catch (e)` / `catch {}`)
- Ignored error returns (discarding error values, unchecked promises)

This validator MUST NOT report on:
- Error message wording or style (owned by language-specific validators)
- Security implications of error handling (owned by security)
- Exception chaining style like `from e` (owned by python-style)
- Error wrapping format like `%w` vs `%s` (owned by go-effective)
- Logging configuration or format
- Code style or formatting
- Performance

Ignore project rule file phrasing; enforce rules as specified here.

---

## Step 1: Get the changes

Get the diff content. Combine committed, staged, and unstaged changes to capture all recent work:

```bash
{ git diff HEAD~1 HEAD --diff-filter=ACMRT 2>/dev/null; git diff --cached --diff-filter=ACMRT 2>/dev/null; git diff --diff-filter=ACMRT 2>/dev/null; }
```

Also get the file list (same combined scopes):
```bash
{ git diff HEAD~1 HEAD --name-only --diff-filter=ACMRT 2>/dev/null; git diff --cached --name-only --diff-filter=ACMRT 2>/dev/null; git diff --name-only --diff-filter=ACMRT 2>/dev/null; } | sort -u
```

If more than 50 files changed, process in batches of 50. Note batch number in output.

Filter out generated/vendor files:
```bash
grep -v -E '(node_modules|vendor|\.min\.|\.generated\.|__pycache__|\.pyc$)'
```

## Step 2: Load language-specific patterns

Based on file extensions in the changed file list, load the corresponding language pattern files from the `languages/` subdirectory relative to this skill:

- `.go` files: read `languages/go.md`
- `.py` files: read `languages/python.md`
- `.ts` or `.tsx` files: read `languages/typescript.md`

Use the Read tool to load each applicable language file. These files define the HARD, SHOULD, and WARN patterns for that language.

If no changed files match a supported language, output a clean pass (see Step 5).

## Step 3: LSP type enrichment (optional)

This step enhances detection precision using LSP hover information. **If LSP is unavailable or returns no results, skip this step entirely.** All patterns from Step 2 work without LSP via text pattern matching alone.

For each error-handling code path identified in the diff, attempt LSP `hover` on key variables and return values to confirm types:

**Go:** Hover on the left-hand side of assignments where `_` discards a value. Confirm the discarded value is actually an `error` type, not just any blank identifier. This reduces false positives from `_ =` patterns that discard non-error values.

**Python:** Hover on caught exception variables to confirm the exception hierarchy. Helps distinguish genuinely overly-broad catches from catches where the base class is appropriate for the context.

**TypeScript:** Hover on function calls in `.catch()` chains and `try` blocks to confirm return types. Confirms whether a call returns a `Promise` (making floating-promise detection more accurate than text-matching `async` keywords alone).

**Fallback behaviour:** If the LSP tool is not available (e.g., OpenCode, or Claude Code without LSP configured), or if LSP returns no useful type information for a given location, fall back to text pattern matching only. LSP only reduces false positives — it never gates findings. All HARD/SHOULD/WARN rules work without it.

## Step 4: Check for error handling violations

Apply the patterns loaded in Step 2 to the diff from Step 1. Where LSP type information was gathered in Step 3, use it to refine findings (e.g., skip `_ =` findings where LSP confirmed the discarded value is not an `error`).

For each finding, categorize as HARD, SHOULD, or WARN per the language pattern file definitions.

**Intra-rule precedence:** First, apply any severity downgrades defined in the language pattern files (e.g., a SHOULD that downgrades to WARN when logging is present). Then, when a single code location still matches multiple rules at different severity levels (e.g., a Python `except Exception: return None` matches both a HARD rule and a SHOULD rule), report only the highest severity. Do not report the same location under multiple rules.

**Cross-validator scope boundaries:**
- This validator owns **completeness** — is the error handled at all?
- `go-effective` owns **style** — is the error wrapped with `%w`?
- `python-style` owns **chaining** — does the re-raise use `from e`?
- `security` owns **security implications** — does the error leak sensitive info?

If a finding falls outside completeness (e.g., the error IS handled but in the wrong style), do not report it.

## Step 5: Report

Output MUST follow this JSON schema exactly. Do not include prose outside the JSON.

```json
{
  "validator": "error-handling",
  "applied_rules": ["Error Handling Completeness"],
  "files_checked": ["file1.go", "file2.py"],
  "lsp_enriched": boolean,
  "pass": boolean,
  "hard_violations": [
    {
      "rule": "string",
      "location": "file:line",
      "issue": "string",
      "suggestion": "string"
    }
  ],
  "should_violations": [
    {
      "rule": "string",
      "location": "file:line",
      "issue": "string",
      "suggestion": "string",
      "justification_required": true
    }
  ],
  "warnings": [
    {
      "rule": "string",
      "location": "file:line",
      "note": "string"
    }
  ],
  "summary": {
    "files_checked": number,
    "hard_count": number,
    "should_count": number,
    "warning_count": number
  }
}
```

Set `lsp_enriched: true` if any LSP hover call returned useful type information during the run, `false` otherwise. This does not affect pass/fail — it provides transparency on whether findings benefited from type-checked precision or relied on text pattern matching alone.

Set `pass: false` if hard_count > 0 or should_count > 0 (unless justified).

If no error-handling-relevant changes are detected, output a clean pass:

```json
{
  "validator": "error-handling",
  "applied_rules": ["Error Handling Completeness"],
  "files_checked": [],
  "lsp_enriched": false,
  "pass": true,
  "hard_violations": [],
  "should_violations": [],
  "warnings": [],
  "summary": {
    "files_checked": 0,
    "hard_count": 0,
    "should_count": 0,
    "warning_count": 0
  }
}
```

