Skip to content
cccskills
FreePublished on GitHub

error-handling-patterns

Production-grade error handling for Node.js/TypeScript backends. Error classes, HTTP mapping, logging, retry strategies.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md3.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Error Class Hierarchy

// Base application error
export class AppError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly statusCode: number = 500,
    public readonly context?: Record<string, unknown>
  ) {
    super(message);
    this.name = this.constructor.name;
    Error.captureStackTrace(this, this.constructor);
  }
}

// Domain-specific errors
export class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super(`${resource} not found: ${id}`, 'NOT_FOUND', 404, { resource, id });
  }
}

export class ValidationError extends AppError {
  constructor(field: string, message: string) {
    super(message, 'VALIDATION_ERROR', 400, { field });
  }
}

export class UnauthorizedError extends AppError {
  constructor(message = 'Unauthorized') {
    super(message, 'UNAUTHORIZED', 401);
  }
}

export class ConflictError extends AppError {
  constructor(resource: string) {
    super(`${resource} already exists`, 'CONFLICT', 409, { resource });
  }
}

Express Error Middleware

// Always the LAST middleware
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({
      error: {
        code: err.code,
        message: err.message,
        ...(process.env.NODE_ENV === 'development' ? { context: err.context } : {}),
      },
    });
  }

  // Unexpected error — log and return 500
  console.error('Unexpected error:', err);
  return res.status(500).json({
    error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' },
  });
});

Async Handler Wrapper

// Eliminates try/catch boilerplate in route handlers
export const asyncHandler = (fn: RequestHandler): RequestHandler =>
  (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);

// Usage
router.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await userService.findById(req.params.id);
  if (!user) throw new NotFoundError('User', req.params.id);
  res.json(user);
}));

Retry Pattern

async function withRetry<T>(
  fn: () => Promise<T>,
  { maxAttempts = 3, delay = 100, backoff = 2 } = {}
): Promise<T> {
  let lastError: Error;
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      lastError = err as Error;
      if (attempt === maxAttempts) break;
      await new Promise(r => setTimeout(r, delay * backoff ** (attempt - 1)));
    }
  }
  throw lastError!;
}

// Usage
const user = await withRetry(() => db.user.findUnique({ where: { id } }));

Result Type (No-throw Alternative)

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

async function safeGetUser(id: string): Promise<Result<User>> {
  try {
    const user = await db.user.findUnique({ where: { id } });
    if (!user) return { ok: false, error: new NotFoundError('User', id) };
    return { ok: true, value: user };
  } catch (err) {
    return { ok: false, error: err as Error };
  }
}

Checklist

  • All error types extend AppError
  • HTTP status codes correctly mapped (400 client, 500 server)
  • Unexpected errors logged with context
  • Async routes wrapped (no unhandled rejections)
  • Sensitive data NOT in error responses (no stack traces in prod)

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

anoa

Free

Drive a real browser from the command line — open pages, snapshot the interactive elements as refs, click and fill by ref, read text, run JS, screenshot. Use when a task needs a live browser: checking a page renders, walking a login or checkout flow, scraping something that only exists after JavaScript runs, or reproducing a UI bug.

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Run linters/typecheckers to calculate health score.

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Comprehensive UI/UX compliance check (A11y, performance, responsive).

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Infrastructure-first security audit (OWASP, secrets, dependencies).

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

auth

Free

Setup authentication flow (register, login, session/JWT, middleware)

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

Deep knowledge about deploying applications to AWS (EC2, ECS, S3, CloudFront, Cloud Run).

The English summary is being prepared. Showing the original description.

porcupine-md/jonggrang16Updated Sep 15, 2026

See all skills by porcupine-md

Report a problem with this skill