error-handling
Handle errors consistently across frontend and backend. Use when implementing try/catch patterns, error boundaries, API error responses, or error reporting.
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.
| name | error-handling |
|---|---|
| description | Handle errors consistently across frontend and backend. Use when implementing try/catch patterns, error boundaries, API error responses, or error reporting. |
| allowed-tools | Read, 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.onerrorhandler 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
Related Skills
- 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