How Do You Handle Uncaught Exceptions in Node.js?
How to handle uncaught exceptions in Node.js using uncaughtException and unhandledRejection, log errors, shut down gracefully, and auto-restart cleanly.
Expected Interview Answer
Uncaught exceptions are errors that bubble up without being caught by any try/catch or promise handler; you handle them by listening to process.on('uncaughtException') and process.on('unhandledRejection'), logging the error, and then gracefully shutting the process down.
The recommended pattern is to treat an uncaught exception as an unrecoverable state: log it, release resources, and let the process exit so a manager like PM2, systemd, or Kubernetes restarts a clean instance. You should not keep the process running after an uncaughtException because the application may be in a corrupted state. For asynchronous errors, unhandledRejection catches rejected promises that lack a .catch, and domain-level solutions or async error middleware handle request-scoped failures.
- Prevents silent crashes and hidden failures
- Enables logging and alerting before exit
- Allows graceful cleanup of connections and files
- Works with process managers for auto-restart
- Catches stray promise rejections
AI Mentor Explanation
An uncaught exception is like a ball flying past every fielder to the boundary because nobody was positioned to stop it. A good captain does not pretend the over continues normally; he notes what went wrong, resets the field, and often the umpires pause play. In Node.js you catch the loose ball with process.on('uncaughtException'), record it, then restart cleanly rather than playing on in disarray.
Step-by-Step Explanation
Step 1
Listen for uncaughtException
Register process.on('uncaughtException', handler) as a last-resort catch for synchronous errors that escaped all try/catch blocks.
Step 2
Catch unhandled rejections
Register process.on('unhandledRejection', handler) for promises rejected without a .catch handler.
Step 3
Log with full context
Record the error, stack trace, and any diagnostic data to your logging or monitoring system before exiting.
Step 4
Clean up resources
Close database connections, flush logs, and stop the server so no requests hang.
Step 5
Exit and let a manager restart
Call process.exit(1) so PM2, systemd, or Kubernetes replaces the corrupted process with a fresh one.
What Interviewer Expects
- Knowing uncaughtException and unhandledRejection events
- Understanding why you should exit rather than resume
- Awareness of graceful shutdown and cleanup
- Reliance on process managers for auto-restart
- Difference between synchronous and asynchronous error handling
Common Mistakes
- Keeping the process alive after an uncaughtException
- Using uncaughtException as normal control flow instead of try/catch
- Ignoring unhandledRejection for promises
- Not logging the error before exiting
- Forgetting to close open connections during shutdown
Best Answer (HR Friendly)
“In Node.js you set up a global listener that catches any error which slipped through the cracks, records what went wrong, tidies up open connections, and then restarts the program cleanly. The safest approach is to log the crash and let a supervisor relaunch a fresh instance rather than continue in a broken state.”
Code Example
process.on('uncaughtException', (err) => {
console.error('Uncaught exception:', err);
// Attempt a graceful cleanup, then exit so a manager restarts us
shutdown(1);
});
process.on('unhandledRejection', (reason) => {
console.error('Unhandled promise rejection:', reason);
shutdown(1);
});
function shutdown(code) {
// Close server, DB pool, flush logs — guard against hanging
server.close(() => {
console.log('Server closed, exiting.');
process.exit(code);
});
// Force-exit if cleanup stalls
setTimeout(() => process.exit(code), 5000).unref();
}Follow-up Questions
- Why should you exit the process after an uncaughtException?
- What is the difference between uncaughtException and unhandledRejection?
- How do process managers like PM2 help with crash recovery?
- How do you implement a graceful shutdown in an Express server?
- What is the role of async error middleware in Express?
MCQ Practice
1. Which event catches a promise rejected with no .catch handler?
process.on('unhandledRejection') fires for promises that reject without any rejection handler attached.
2. What is the recommended action inside an uncaughtException handler?
The process may be in a corrupted state, so best practice is to log, clean up, and exit so a manager restarts a clean instance.
3. Why is uncaughtException a last resort, not normal control flow?
By the time uncaughtException fires the application may be in an inconsistent state, so it should not replace local try/catch handling.
Flash Cards
Which event catches synchronous errors that escaped all try/catch? — process.on('uncaughtException').
Which event catches unhandled promise rejections? — process.on('unhandledRejection').
Should you keep running after an uncaughtException? — No — log, clean up, and exit so a manager restarts a fresh process.
What tools restart a crashed Node.js process? — Process managers like PM2, systemd, or Kubernetes.