From harness-claude
Implements global error handling for Node.js apps: uncaught exceptions, unhandled rejections, async Express wrappers, custom error classes, centralized handlers, and graceful shutdowns.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Handle uncaught exceptions, promise rejections, and errors across async Node.js code
Provides error handling patterns like custom errors, structured logging, retries, circuit breakers for JavaScript/TypeScript apps including Express global handlers.
Provides error handling patterns, exception filters, error boundaries, logging, retries, and recovery strategies for React, Next.js, and NestJS apps. Use for async errors, monitoring integration, and graceful degradation.
Implements standardized API error handling with RFC 7807 responses, typed error classes, middleware, and monitoring. Use for consistent HTTP errors across endpoints.
Share bugs, ideas, or general feedback.
Handle uncaught exceptions, promise rejections, and errors across async Node.js code
process.on('uncaughtException', (error, origin) => {
console.error('Uncaught exception:', error);
console.error('Origin:', origin);
// Perform synchronous cleanup, then exit
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled rejection at:', promise, 'reason:', reason);
// In Node.js 15+, unhandled rejections crash the process by default
});
// Express: wrap async handlers
function asyncHandler(fn: (req: Request, res: Response, next: NextFunction) => Promise<void>) {
return (req: Request, res: Response, next: NextFunction) => {
fn(req, res, next).catch(next);
};
}
app.get(
'/users',
asyncHandler(async (req, res) => {
const users = await getUsers(); // Errors are caught
res.json(users);
})
);
class AppError extends Error {
constructor(
message: string,
public statusCode: number = 500,
public code: string = 'INTERNAL_ERROR',
public isOperational: boolean = true
) {
super(message);
this.name = 'AppError';
Error.captureStackTrace(this, this.constructor);
}
}
class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} ${id} not found`, 404, 'NOT_FOUND');
}
}
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
if (err instanceof AppError) {
res.status(err.statusCode).json({
error: { code: err.code, message: err.message },
});
return;
}
// Unexpected error — log full details, return generic message
console.error('Unexpected error:', err);
res.status(500).json({
error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' },
});
}
app.use(errorHandler);
// Operational: expected, recoverable (invalid input, network timeout)
throw new AppError('Email already exists', 400, 'DUPLICATE_EMAIL', true);
// Programmer: unexpected, should crash (null reference, type error)
// Let these propagate to uncaughtException handler
async function gracefulShutdown(signal: string) {
console.log(`Received ${signal}, shutting down gracefully`);
server.close(() => {
db.$disconnect();
process.exit(0);
});
setTimeout(() => {
console.error('Forced shutdown');
process.exit(1);
}, 10_000);
}
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
import { pipeline } from 'node:stream/promises';
try {
await pipeline(readable, transform, writable);
} catch (err) {
// Pipeline handles cleanup of all streams on error
console.error('Pipeline failed:', err);
}
Node.js error handling spans synchronous throws, async rejections, event emitter errors, and process-level handlers. A comprehensive strategy covers all four.
Error propagation layers:
try/catch — synchronous and async/await code.catch() — Promise chains'error' event — EventEmitter instances (streams, servers)process.on('uncaughtException') — last resort for synchronous throwsprocess.on('unhandledRejection') — last resort for unhandled promisesOperational vs programmer errors:
Trade-offs:
process.exit(1) is immediate — but skips cleanup. Use server.close() firsthttps://nodejs.org/api/process.html#event-uncaughtexception