error-handling

majiayu000's avatarfrom majiayu000

Handle errors consistently across frontend and backend. Use when implementing try/catch patterns, error boundaries, API error responses, or error reporting.

⭐5stars🔀1forks📁View on GitHub🕐Updated Jan 11, 2026

When & Why to Use This Skill

This Claude skill provides a comprehensive framework for implementing consistent error handling across the entire software stack. It streamlines the development of resilient JavaScript applications by offering standardized patterns for try/catch blocks, React error boundaries, API error responses, and global exception monitoring. By centralizing error logic, it ensures developers can detect, report, and recover from failures gracefully, significantly improving application stability and observability.

Use Cases

  • Standardizing API error response formats in Node.js backends to ensure consistent communication with frontend clients.
  • Implementing React Error Boundaries to catch component-level crashes and provide graceful fallback UIs.
  • Setting up global error listeners (window.onerror) and unhandled promise rejection handlers for comprehensive frontend monitoring.
  • Creating custom Error classes (e.g., ApiError, ValidationError) to handle specific business logic failures with rich context.
  • Designing robust asynchronous workflows with structured try/catch blocks and retry logic for network-dependent operations.
nameerror-handling
descriptionHandle errors consistently across frontend and backend. Use when implementing try/catch patterns, error boundaries, API error responses, or error reporting.
allowed-toolsRead, Write, Edit, Glob, Grep

Error Handling Skill

Consistent error handling patterns for JavaScript applications.

Core Principles

Principle Description
Fail Fast Detect errors early, at system boundaries
Explicit Errors Never swallow errors silently
Meaningful Messages Errors should explain what went wrong and why
Graceful Degradation Provide fallbacks when possible
Error Tracking Log and report errors for observability

Error Categories

Category Where Pattern
Sync Errors Component lifecycle Error boundaries
Async Errors Promises, fetch try/catch, .catch()
Network Errors API calls Retry logic, offline queuing
Validation Errors Form input, API Field-level messages
System Errors Uncaught exceptions Global handlers

Pattern Quick Reference

Synchronous Errors

// Type guard with assertion
function assertDefined(value, message = 'Value is undefined') {
  if (value === undefined || value === null) {
    throw new Error(message);
  }
  return value;
}

// Defensive programming
function processUser(user) {
  assertDefined(user, 'User is required');
  assertDefined(user.id, 'User ID is required');
  // Safe to use user.id here
}

Asynchronous Errors

// Always handle promise rejections
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error('Fetch failed:', error);
    throw error; // Re-throw for caller to handle
  }
}

Custom Error Classes

// Typed errors with additional context
class ApiError extends Error {
  constructor(status, statusText, body = null) {
    super(`API Error: ${status} ${statusText}`);
    this.name = 'ApiError';
    this.status = status;
    this.body = body;
  }
}

class ValidationError extends Error {
  constructor(field, message) {
    super(`Validation: ${field} - ${message}`);
    this.name = 'ValidationError';
    this.field = field;
  }
}

// Usage
if (error instanceof ApiError && error.status === 401) {
  redirectToLogin();
}

Error Boundaries (Components)

Use the <error-boundary> custom element to catch component errors:

<error-boundary name="user-profile">
  <user-profile user-id="123"></user-profile>
  <template slot="fallback">
    <p>Could not load profile.</p>
  </template>
</error-boundary>

See: /add-error-boundary command for implementation.

Global Error Handlers

// Catch unhandled errors
window.onerror = function(message, source, lineno, colno, error) {
  reportError({
    type: 'uncaught',
    message,
    source,
    line: lineno,
    column: colno,
    stack: error?.stack
  });
  return false; // Allow default handling
};

// Catch unhandled promise rejections
window.onunhandledrejection = function(event) {
  reportError({
    type: 'unhandled-rejection',
    reason: event.reason
  });
};

API Error Responses (Backend)

// Consistent error response format
function errorResponse(res, status, type, message, details = null) {
  res.status(status).json({
    type,
    message,
    ...(details && { details })
  });
}

// Usage in route
app.post('/api/users', (req, res) => {
  const { email, password } = req.body;

  if (!email) {
    return errorResponse(res, 400, 'validation', 'Email is required', {
      field: 'email'
    });
  }

  // ...
});

Error Flow Architecture

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  User Action    │────▶│  Error Handler  │────▶│  Error Report   │
│  (click, input) │     │  (try/catch)    │     │  (logging/API)  │
└─────────────────┘     └─────────────────┘     └─────────────────┘
                               │
                               ▼
                        ┌─────────────────┐
                        │  User Feedback  │
                        │  (toast/inline) │
                        └─────────────────┘

User Feedback Patterns

Error Type Feedback Example
Validation Inline field error "Email is required"
Network Toast notification "Connection lost. Retrying..."
Auth Redirect or modal Redirect to login
Server Generic message "Something went wrong"
Not Found 404 page or inline "Resource not found"
// Centralized error display
function showError(error, options = {}) {
  const { type = 'toast', duration = 5000 } = options;

  if (type === 'inline' && options.container) {
    options.container.innerHTML = `
      <div class="error-message" role="alert">
        ${error.message}
      </div>
    `;
  } else {
    // Toast notification
    const toast = document.createElement('div');
    toast.className = 'toast toast--error';
    toast.setAttribute('role', 'alert');
    toast.textContent = error.message;
    document.body.appendChild(toast);

    setTimeout(() => toast.remove(), duration);
  }
}

Detailed Implementation

For comprehensive patterns, see these related skills:

Skill Coverage
observability Global handlers, error reporting, Web Vitals
api-client API errors, retry logic, typed responses
javascript-author Defensive patterns, type guards
nodejs-backend Server error middleware, logging
logging Structured error logging

Checklist

When implementing error handling:

Frontend

  • Global window.onerror handler installed
  • Unhandled promise rejections caught
  • Error boundaries wrap risky components
  • Async functions wrapped with try/catch
  • User-friendly error messages shown
  • Errors reported to monitoring service

Backend

  • Consistent error response format
  • Errors logged with context (request ID, user)
  • Sensitive data not exposed in errors
  • Validation errors return field-level details
  • 5xx errors trigger alerts

Both

  • Custom error classes for typed handling
  • Errors re-thrown after logging (not swallowed)
  • Stack traces available in development
  • Generic messages in production
  • validation - JSON Schema validation with AJV, ValidationError patterns
  • observability - Error tracking, performance monitoring
  • api-client - Fetch error patterns, retry logic
  • javascript-author - Defensive programming, type guards
  • nodejs-backend - Server-side error handling
  • logging - Structured error logging