CtrlK
BlogDocsLog inGet started
Tessl Logo

peteski22/error-handling

Validate error handling completeness across languages

46

Quality

57%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files
name:
error-handling
description:
Validate error handling completeness across languages
context:
fork
agent:
general-purpose
user-invocable:
No
allowed-tools:
Bash, Read, Grep, Glob, LSP

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 changed files. Try in order until one succeeds:

# 1. Committed changes (diff content).
git diff HEAD~1 --diff-filter=ACMRT

# 2. Staged changes.
git diff --cached --diff-filter=ACMRT

# 3. Unstaged changes.
git diff --diff-filter=ACMRT

Also get the file list (same fallback order):

git diff HEAD~1 --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

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

Filter out generated/vendor files:

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.

{
  "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:

{
  "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
  }
}
Workspace
peteski22
Visibility
Public
Created
Last updated
Publish Source
GitHub
Badge
peteski22/error-handling badge