install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/node-error-handling" ~/.claude/skills/intense-visions-harness-engineering-node-error-handling && rm -rf "$T"
manifest:
agents/skills/claude-code/node-error-handling/SKILL.mdsource content
Node.js Error Handling
Handle uncaught exceptions, promise rejections, and errors across async Node.js code
When to Use
- Setting up global error handling for a Node.js application
- Preventing the process from crashing on unhandled errors
- Implementing structured error handling across async code
- Logging and recovering from errors in production
Instructions
- Handle uncaught exceptions — log and exit:
process.on('uncaughtException', (error, origin) => { console.error('Uncaught exception:', error); console.error('Origin:', origin); // Perform synchronous cleanup, then exit process.exit(1); });
- Handle unhandled promise rejections:
process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled rejection at:', promise, 'reason:', reason); // In Node.js 15+, unhandled rejections crash the process by default });
- Always catch async errors:
// 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); }) );
- Custom error classes:
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'); } }
- Centralized error handler:
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 vs programmer errors:
// 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
- Graceful shutdown on fatal errors:
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'));
- Error handling in streams:
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); }
Details
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:
— synchronous andtry/catch
codeasync/await
— Promise chains.catch()
event — EventEmitter instances (streams, servers)'error'
— last resort for synchronous throwsprocess.on('uncaughtException')
— last resort for unhandled promisesprocess.on('unhandledRejection')
Operational vs programmer errors:
- Operational: expected failures that the application can handle (validation errors, timeouts, 404s)
- Programmer: bugs in the code (null dereference, wrong arguments, logic errors)
- Operational errors should be caught and handled; programmer errors should crash the process (in production, use a process manager like PM2 to restart)
Trade-offs:
- Global error handlers catch everything — but should only log and exit, not attempt recovery
- Custom error classes enable structured handling — but add code for each error type
- Graceful shutdown preserves data integrity — but adds shutdown complexity
is immediate — but skips cleanup. Useprocess.exit(1)
firstserver.close()
Source
https://nodejs.org/api/process.html#event-uncaughtexception
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.