skills/code-quality/cleanup-defensive/SKILL.md
Remove pointless try/catch blocks and defensive guards that hide errors or add no value. Preserves catches at true system boundaries (HTTP handlers, CLI entry, message consumers). Use when the user asks to remove try/catch, fix error hiding, clean up defensive code, or stop swallowing errors.
npx skillsauth add raintree-technology/claude-starter cleanup-defensiveInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Remove try/catch and defensive null-checks that don't serve a real role. The goal is errors that propagate cleanly to the boundary that knows how to handle them, not silent fallbacks that hide bugs.
Core principle: catch only when you can do something more useful than the default propagation — and "log and rethrow" is rarely more useful than just letting it throw.
if err != nil patterns), Rust (unwrap_or/map_err chains that smell defensive).app/api/, routes/, Hono/Express/FastAPI handlers)if __name__ == "__main__", bin/*, cmd/*)# Find every try/catch
grep -rn --include="*.ts" --include="*.tsx" --include="*.js" -B1 -A5 "try {" \
--exclude-dir=node_modules --exclude-dir=.next . > /tmp/try-catches.txt
# ESLint can flag the obvious useless ones
npx eslint --rule '{"no-useless-catch": "error"}' --no-eslintrc . 2>&1 | grep no-useless-catch > /tmp/useless-catch.txt
Categorize each catch block by content:
catch (e) { throw e } or catch (e) { throw new Error(...) } with no context addedcatch { return null }, catch { return [] }, catch { return {} }catch (e) { console.error(e) } then continue silentlycatch (e) { logger.error(e); throw e } — usually pointless if a global handler logsgrep -rn --include="*.py" -B1 -A5 "try:" . > /tmp/py-try.txt
# Bare except is always defensive
grep -rn --include="*.py" -E "except\s*:|except\s+Exception\s*:" . > /tmp/py-bare-except.txt
# Find error-swallowing patterns: ignored errors, generic fallbacks
grep -rn --include="*.go" -E "_ = .*\.Err|_, _ =" . > /tmp/go-ignored.txt
grep -rn --include="*.rs" -E "\.unwrap_or\(|\.unwrap_or_default\(|\.ok\(\)" . > /tmp/rust-defensive.txt
Write .claude/cleanup-reports/cleanup-defensive-{YYYY-MM-DD}.md:
# Defensive Code Assessment — YYYY-MM-DD
## Summary
- try/catch blocks scanned: N
- HIGH (remove): X — pure rethrow, swallow-and-return-null, useless wrappers
- MEDIUM (review): Y — log+rethrow, broad excepts with context
- LOW (preserve): Z — substantive handling, boundary code
## Findings
### HIGH — `lib/parse.ts:45`
```ts
try {
return JSON.parse(s)
} catch (e) {
return null
}
Problem: caller can't distinguish "valid JSON null" from "parse failed". Hides bugs.
Fix: remove try; let JSON.parse throw. If callers need optional, change return to Result<T, ParseError> or have caller wrap.
services/user.ts:88try {
return await fetchUser(id)
} catch (e) {
throw e
}
Problem: literally a no-op wrapper. Fix: remove try/catch entirely.
services/payment.ts:120try {
await charge(amount)
} catch (e) {
logger.error('charge failed', { e, userId })
throw e
}
Problem: log+rethrow. If global handler also logs, this is duplication.
Recommendation: check if there's a global error logger. If yes, remove. If the contextual data (userId) isn't otherwise captured, keep but add a note.
app/api/[...path]/route.ts:34 — preserve, this is the API boundary.[2-3 paragraphs on patterns: is this codebase prone to silent fallbacks? Are there layers wrapping errors unnecessarily?]
## Apply
**Auto-remove HIGH only.**
### Confidence rubric
**HIGH (auto-remove):**
- `try { x } catch { } ` (silent swallow, no return)
- `try { x } catch (e) { throw e }` (no-op)
- `try { x } catch (e) { throw new Error(e.message) }` (loses stack, adds nothing)
- `try { x } catch { return null/undefined/[]/{}/0 }` (silent fallback that hides errors) — only if file is NOT a boundary file
- Python `except: pass` blocks
- Go: `_ = someCall()` where the discarded value is `error`
**MEDIUM (report only):**
- Log + rethrow (might be intentional observability)
- Catch with retry logic
- Catch in middleware (might be intentional last-resort)
- `unwrap_or(default)` where default is a real value (might be intentional)
**LOW (preserve):**
- Inside boundary files (see preflight list)
- Inside `__init__.py` import-time error handlers (compatibility fallbacks)
- Catches that transform exception type meaningfully (e.g., `catch DBError { throw new ValidationError() }`)
- Cleanup catches with `finally` doing real work
### Execution
For each HIGH:
1. Remove the try wrapper, keep the body's expression.
2. If the function signature implied "may return null on error" because of the catch, that signature is now lying — flag for human review (do NOT change signatures automatically).
3. Single commit: `chore(cleanup): cleanup-defensive — removed N useless try/catch blocks`.
## Verify
```bash
npm run check 2>&1 || (npx tsc --noEmit && npx eslint .)
npm test 2>&1
pytest 2>&1
go test ./... 2>&1
cargo test 2>&1
Tests are critical here — removing a swallowed error often surfaces a real bug that was being hidden. If tests fail:
finally that does cleanup (closing resources, releasing locks).if err != nil { return err } patterns — that IS the proper Go way, not defensive code.unwrap() from Rust without understanding the precondition; replacement should be expect("reason") minimum, or proper handling.except without checking if it's catching a specific expected exception.development
Whop platform expert for digital products, memberships, and community monetization. Covers memberships API, payments, courses, forums, webhooks, OAuth apps, and checkout integration. Build SaaS, course platforms, and gated communities. Triggers on Whop, memberships, digital products, course platform, community monetization, Whop API, license keys.
development
Token-Oriented Object Notation (TOON) format expert for 30-60% token savings on structured data. Auto-applies to arrays with 5+ items, tables, logs, API responses, database results. Supports tabular, inline, and expanded formats with comma/tab/pipe delimiters. Triggers on large JSON, data optimization, token reduction, structured data, arrays, tables, logs, metrics, TOON.
development
Plaid banking API expert for financial data integration. Covers Plaid Link, Auth (account/routing numbers), Transactions, Identity verification, Balance checking, and webhooks. Build fintech apps with bank connections, ACH transfers, and transaction history. Triggers on Plaid, banking API, Plaid Link, bank connection, ACH, financial data, transaction history.
development
Helius Solana RPC and API expert. High-performance infrastructure for Solana including RPC nodes, DAS API for NFTs/tokens, LaserStream real-time streaming, webhooks, Priority Fee API, Enhanced Transactions, and ZK Compression. Triggers on Helius, Solana RPC, DAS API, Digital Asset Standard, NFT metadata, Solana webhooks, priority fees, LaserStream, ZK compression.