Error Class Hierarchy Builder
Prerequisites & Dependencies
- Node.js 18+ or Python 3.10+, TypeScript strongly preferred
- Understanding of try/catch blocks and error propagation
- Optional:
npm i @types/node for TS, or built-in http/status codes
Execution Steps
- Define a base custom error class that captures domain-wide concerns:
errorCode, httpStatus, metadata (retry-after, correlation ID, etc.)
- Extend the hierarchy for specific domains: validation errors, authentication failures, not-found resources, server errors
- Standardize the constructor signature:
new AppError(message, httpStatus, metadata) across all subclasses
- Add helper methods:
isOperational, sendDev, sendProd (different error output for dev vs prod)
- Use the hierarchy consistently across the codebase, replacing generic
try/catch with typed catches
- Document the error taxonomy and ensure all team members throw/customize errors using the same pattern
// Base AppError with code, status, and metadata
class AppError extends Error {
public readonly errorCode: string;
public readonly httpStatus: number;
public readonly metadata: Record<string, unknown>;
constructor(message: string, httpStatus = 500, metadata: Record<string, unknown> = {}) {
super(message);
this.name = 'AppError';
this.errorCode = metadata.code || 'UNKNOWN_ERROR';
this.httpStatus = httpStatus;
this.metadata = metadata;
Error.captureStackTrace(this, this.constructor);
}
}
// Domain-specific subclasses
class ValidationError extends AppError {
constructor(message: string, metadata?: Record<string, unknown>) {
super(message, 400, metadata || { code: 'VALIDATION_ERROR' });
}
}
class NotFoundError extends AppError {
constructor(resource: string, id: string, metadata?: Record<string, unknown>) {
super(` ${resource} with id ${id} not found`, 404, metadata || { code: 'NOT_FOUND' });
}
}
// Usage in an Express handler
app.get('/users/:id', async (req, res, next) => {
try {
const user = await db.findById(req.params.id);
if (!user) throw new NotFoundError('User', req.params.id);
res.json(user);
} catch (err) {
next(err); // centralized error handler formats response
}
});
1---2name: error-class-hierarchy-builder3description: Create domain-specific custom exception classes with standardized error codes, HTTP statuses, and metadata payloads.4metadata:5 source: skills/error-class-hierarchy-builder/error-class-hierarchy-builder.md6---78# Error Class Hierarchy Builder910## Prerequisites & Dependencies11- Node.js 18+ or Python 3.10+, TypeScript strongly preferred12- Understanding of try/catch blocks and error propagation13- Optional: `npm i @types/node` for TS, or built-in `http`/`status` codes1415## Execution Steps161. Define a base custom error class that captures domain-wide concerns: `errorCode`, `httpStatus`, `metadata` (retry-after, correlation ID, etc.)172. Extend the hierarchy for specific domains: validation errors, authentication failures, not-found resources, server errors183. Standardize the constructor signature: `new AppError(message, httpStatus, metadata)` across all subclasses194. Add helper methods: `isOperational`, `sendDev`, `sendProd` (different error output for dev vs prod)205. Use the hierarchy consistently across the codebase, replacing generic `try/catch` with typed catches216. Document the error taxonomy and ensure all team members throw/customize errors using the same pattern2223```typescript24// Base AppError with code, status, and metadata25class AppError extends Error {26 public readonly errorCode: string;27 public readonly httpStatus: number;28 public readonly metadata: Record<string, unknown>;2930 constructor(message: string, httpStatus = 500, metadata: Record<string, unknown> = {}) {31 super(message);32 this.name = 'AppError';33 this.errorCode = metadata.code || 'UNKNOWN_ERROR';34 this.httpStatus = httpStatus;35 this.metadata = metadata;36 Error.captureStackTrace(this, this.constructor);37 }38}3940// Domain-specific subclasses41class ValidationError extends AppError {42 constructor(message: string, metadata?: Record<string, unknown>) {43 super(message, 400, metadata || { code: 'VALIDATION_ERROR' });44 }45}4647class NotFoundError extends AppError {48 constructor(resource: string, id: string, metadata?: Record<string, unknown>) {49 super(` ${resource} with id ${id} not found`, 404, metadata || { code: 'NOT_FOUND' });50 }51}5253// Usage in an Express handler54app.get('/users/:id', async (req, res, next) => {55 try {56 const user = await db.findById(req.params.id);57 if (!user) throw new NotFoundError('User', req.params.id);58 res.json(user);59 } catch (err) {60 next(err); // centralized error handler formats response61 }62});63```