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.4---56# Error Class Hierarchy Builder78## Prerequisites & Dependencies9- Node.js 18+ or Python 3.10+, TypeScript strongly preferred10- Understanding of try/catch blocks and error propagation11- Optional: `npm i @types/node` for TS, or built-in `http`/`status` codes1213## Execution Steps141. Define a base custom error class that captures domain-wide concerns: `errorCode`, `httpStatus`, `metadata` (retry-after, correlation ID, etc.)152. Extend the hierarchy for specific domains: validation errors, authentication failures, not-found resources, server errors163. Standardize the constructor signature: `new AppError(message, httpStatus, metadata)` across all subclasses174. Add helper methods: `isOperational`, `sendDev`, `sendProd` (different error output for dev vs prod)185. Use the hierarchy consistently across the codebase, replacing generic `try/catch` with typed catches196. Document the error taxonomy and ensure all team members throw/customize errors using the same pattern2021```typescript22// Base AppError with code, status, and metadata23class AppError extends Error {24 public readonly errorCode: string;25 public readonly httpStatus: number;26 public readonly metadata: Record<string, unknown>;2728 constructor(message: string, httpStatus = 500, metadata: Record<string, unknown> = {}) {29 super(message);30 this.name = 'AppError';31 this.errorCode = metadata.code || 'UNKNOWN_ERROR';32 this.httpStatus = httpStatus;33 this.metadata = metadata;34 Error.captureStackTrace(this, this.constructor);35 }36}3738// Domain-specific subclasses39class ValidationError extends AppError {40 constructor(message: string, metadata?: Record<string, unknown>) {41 super(message, 400, metadata || { code: 'VALIDATION_ERROR' });42 }43}4445class NotFoundError extends AppError {46 constructor(resource: string, id: string, metadata?: Record<string, unknown>) {47 super(` ${resource} with id ${id} not found`, 404, metadata || { code: 'NOT_FOUND' });48 }49}5051// Usage in an Express handler52app.get('/users/:id', async (req, res, next) => {53 try {54 const user = await db.findById(req.params.id);55 if (!user) throw new NotFoundError('User', req.params.id);56 res.json(user);57 } catch (err) {58 next(err); // centralized error handler formats response59 }60});61```