Skip to content
Skillpedia
General coding280k · #53

error-handling

Helps your agent handle errors robustly across different languages. It defines how errors are managed, recovers from failures, and informs the user.

What it does

This skill teaches how to handle errors in computer programs. It helps ensure programs don't crash unexpectedly and that users receive clear messages when something goes wrong.

When to use it

  • ✓When creating a new program or part of one.
  • ✓When a program needs to connect to other services.
  • ✓When thinking about how to show error messages to users.

Example of what to ask your AI

“How can I ensure my program tells the user nicely if it can't find an item?”

Want more? Open the sections below.

How to use

The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.

Skill link

https://github.com/affaan-m/ECC/blob/main/pi/core/skills/error-handling/SKILL.md

Ready-to-paste message

Use this skill to help me: https://github.com/affaan-m/ECC/blob/main/pi/core/skills/error-handling/SKILL.md Read the SKILL.md file at that link and follow its instructions for my task.
How it works

It suggests using error 'types' to understand what happened and creating different messages for the user and the programmer. It also teaches not to ignore errors and to handle failures consistently.

Installation

Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.

In the terminal (Claude Code, Codex, Cursor), in your project folder:

npx skills add affaan-m/ECC --skill error-handling

Or download just the file:

curl -L https://raw.githubusercontent.com/affaan-m/ECC/main/pi/core/skills/error-handling/SKILL.md -o SKILL.md
Technical content (original SKILL.md)

Original text by the author, straight from GitHub.

Error Handling Patterns

Consistent, robust error handling patterns for production applications.

When to Activate

  • Designing error types or exception hierarchies for a new module or service
  • Adding retry logic or circuit breakers for unreliable external dependencies
  • Reviewing API endpoints for missing error handling
  • Implementing user-facing error messages and feedback
  • Debugging cascading failures or silent error swallowing

Core Principles

  1. Fail fast and loudly — surface errors at the boundary where they occur; don't bury them
  2. Typed errors over string messages — errors are first-class values with structure
  3. User messages ≠ developer messages — show friendly text to users, log full context server-side
  4. Never swallow errors silently — every catch block must either handle, re-throw, or log
  5. Errors are part of your API contract — document every error code a client may receive

TypeScript / JavaScript

Typed Error Classes

// Define an error hierarchy for your domain
export class AppError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly statusCode: number = 500,
    public readonly details?: unknown,
  ) {
    super(message)
    this.name = this.constructor.name
    // Maintain correct prototype chain in transpiled ES5 JavaScript.
    // Required for `instanceof` checks (e.g., `error instanceof NotFoundError`)
    // to work correctly when extending the built-in Error class.
    Object.setPrototypeOf(this, new.target.prototype)
  }
}

export class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super(`${resource} not found: ${id}`, 'NOT_FOUND', 404)
  }
}

export class ValidationError extends AppError {
  constructor(message: string, details: { field: string; message: string }[]) {
    super(message, 'VALIDATION_ERROR', 422, details)
  }
}

export class UnauthorizedError extends AppError {
  constructor(reason = 'Authentication required') {
    super(reason, 'UNAUTHORIZED', 401)
  }
}

export class RateLimitError extends AppError {
  constructor(public readonly retryAfterMs: number) {
    super('Rate limit exceeded', 'RATE_LIMITED', 429)
  }
}

Result Pattern (no-throw style)

For operations where failure is expected and common (parsing, external calls):

type Result<T, E = AppError> =
  | { ok: true; value: T }
  | { ok: false; error: E }

function ok<T>(value: T): Result<T> {
  return { ok: true, value }
}

function err<E>(error: E): Result<never, E> {
  return { ok: false, error }
}

// Usage
async function fetchUser(id: string): Promise<Result<User>> {
  try {
    const user = await db.users.findUnique({ where: { id } })
    if (!user) return err(new NotFoundError('User', id))
    return ok(user)
  } catch (e) {
    return err(new AppError('Database error', 'DB_ERROR'))
  }
}

const result = await fetchUser('abc-123')
if (!result.ok) {
  // TypeScript knows result.error here
  logger.error('Failed to fetch user', { error: result.error })
  return
}
// TypeScript knows result.value here
console.log(result.value.email)

API Error Handler (Next.js / Express)

import { NextRequest, NextResponse } from 'next/server'

function handleApiError(error: unknown): NextResponse {
  // Known application error
  if (error instanceof AppError) {
    return NextResponse.json(
      {
        error: {
          code: error.code,
          message: error.message,
          ...(error.details ? { details: error.details } : {}),
        },
      },
      { status: error.statusCode },
    )
  }

  // Zod validation error
  if (error instanceof z.ZodError) {
    return NextResponse.json(
      {
        error: {
          code: 'VALIDATION_ERROR',
          message: 'Request validation failed',
          details: error.issues.map(i => ({
            field: i.path.join('.'),
            message: i.message,
          })),
        },
      },
      { status: 422 },
    )
  }

  // Unexpected error — log details, return generic message
  console.error('Unexpected error:', error)
  return NextResponse.json(
    { error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' } },
    { status: 500 },
  )
}

export async function POST(req: NextRequest) {
  try {
    // ... handler logic
  } catch (error) {
    return handleApiError(error)
  }
}

React Error Boundary


…
FAQ

Why is error handling important?

Handling errors prevents programs from crashing, helps identify problems quickly, and ensures a better user experience by providing clear feedback instead of confusing messages.

What are 'typed errors'?

These are errors that have structured information (like a specific code and message), rather than just being plain text. This helps the program better understand the type of problem.

Should I show the same error message to the user and the programmer?

No. For the user, use simple, friendly messages. For the programmer (in logs, for example), include technical details to help with debugging.

Details

Original description by the author

Patterns for robust error handling across TypeScript, Python, and Go. Covers typed errors, error boundaries, retries, circuit breakers, and user-facing error messages. Use when designing error types, retries, circuit breakers, or user-facing failure messages in TypeScript, Python, or Go.

repo: affaan-m/ECC

Popularity

GitHub stars
280k
Ranking position
#53
License
MIT
Updated
10/15/2026

Is this skill useful?

0

Sign in to vote.

Comments

  • …

More skills from this repository

Similar skills