handling-errors

- Never swallow errors - Empty catch blocks hide bugs that surface later in unrelated places, making them much harder to trace

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "handling-errors" with this command: npx skills add rileyhilliard/claude-essentials/rileyhilliard-claude-essentials-handling-errors

Handling Errors

Iron Laws

  • Never swallow errors - Empty catch blocks hide bugs that surface later in unrelated places, making them much harder to trace

  • Never convert errors to booleans - Loses all context and forces callers to guess what went wrong

  • Preserve error context when wrapping or propagating - upstream handlers need the original cause to make good decisions

  • Log once where handled, not at every layer - duplicate logs across layers create noise that obscures the real signal

Error Messages

Every error message answers: What happened? Why? How to recover?

For logs (developers):

logger.error("Failed to save user: Connection timeout after 30s", { userId: user.id, dbHost: config.db.host, error: error.stack, });

For users:

For user-facing error copy, use Skill(ce:writer) with The UX Writer persona. Key principles:

  • Brief and specific (not "Something went wrong")

  • Actionable (tell them what to do next)

  • No blame (never "You entered invalid...")

showError({ title: "Upload failed", message: "File exceeds 10MB limit. Choose a smaller file.", actions: [{ label: "Choose file", onClick: selectFile }], });

Error Categories

Type Examples Handling

Expected Validation, Not found, Unauthorized Return Result type, log info

Transient Network timeout, Rate limit Retry with backoff, log warn

Unexpected Null reference, DB crash Log error, show support ID

Critical Auth down, Payment gateway offline Circuit breaker, alert

Fail Fast vs Degrade Gracefully

Fail fast for critical dependencies:

await connectToDatabase(); // Throws on failure - app can't run without it

Degrade gracefully for optional features:

const prefs = await loadPreferences(userId).catch(() => DEFAULT_PREFS);

Log at the Right Layer

// ❌ Logging at every layer = same error 3x async function fetchData() { try { return await fetch(url); } catch (e) { console.error("Fetch failed:", e); throw e; } }

// ✅ Log once where handled async function fetchData() { const response = await fetch(url); if (!response.ok) throw new Error(HTTP ${response.status}); return response; } // Top level logs the error once

Language-Specific Patterns

  • TypeScript/React: See references/typescript-react.md for Error Boundaries, typed errors, Result pattern, UI display

  • Python: See references/python.md for EAFP, exception chaining, context managers

  • Go: See references/go.md for explicit error returns, wrapping with %w, sentinel errors

Anti-Patterns

Pattern Problem Fix

Empty catch blocks Hides errors Log or re-throw

return false on error Loses context Return Result type

Generic "Error" messages Undebuggable Include what/why/context

Logging same error at each layer Log pollution Log once at boundary

Bare except: / catch (e) all Catches system signals Catch specific types

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

writer

No summary provided by upstream source.

Repository SourceNeeds Review
General

strategy-writer

No summary provided by upstream source.

Repository SourceNeeds Review
General

reading-logs

No summary provided by upstream source.

Repository SourceNeeds Review