Course contentsShow
← Node.js
Lesson 182 of 1,9803. Asynchronous Patterns and Flow ControlFree lesson

Handling Unhandled Promise Rejections

You will implement centralized logging and process-level crash safety to prevent silent failures in Node.js applications.

Handling Unhandled Promise Rejections

In this lesson, you’ll learn how to prevent your Node.js application from failing silently by capturing errors that occur within Promises that haven't been attached to a .catch() block.

When a Promise rejects and you don't provide an error handler, Node.js treats this as a "silent failure." While older versions of Node.js would let these slide (leading to unpredictable states), modern versions emit an unhandledRejection event. If you don't explicitly listen for this, your application might continue running in a corrupted state or crash without providing useful debugging information.

To ensure your application is resilient, you should implement a centralized listener at the process level. This acts as a safety net to log the error and decide how the process should shut down.

Centralized Logging and Crash Safety

You can hook into the process object to capture these rogue rejections. Here is how you implement a safety net:

// Centralized Error Logger
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
  
  // Perform necessary cleanup before exiting
  // For example: closing database connections or flushing logs
  process.exit(1);
});

// A floating promise that would normally fail silently
Promise.reject(new Error('Database connection failed!'));

By listening to the unhandledRejection event, you transform a silent, invisible failure into a structured event. Instead of letting the runtime guess what to do, you explicitly log the reason (the error object) and the specific promise that failed.

Calling process.exit(1) is a standard "fail-fast" practice in production environments. By exiting with a non-zero code, you signal to your process manager (like PM2 or Kubernetes) that the container has crashed, which triggers a clean restart and prevents the application from lingering in a broken state. This ensures your logs contain the evidence needed to fix the root cause, rather than leaving you to hunt down "ghost" bugs.

Key Takeaway: Always register a global unhandledRejection handler to transform silent failures into actionable logs and controlled process terminations.