Node.js

How to find which promises are unhandled in Nodejs UnhandledPromiseRejectionWarning

27 September 2026 · 9 min read

How to find which promises are unhandled in Nodejs UnhandledPromiseRejectionWarning

Debugging asynchronous JavaScript code, particularly in Node.js, can sometimes feel like navigating a maze. One common pitfall developers encounter is the dreaded UnhandledPromiseRejectionWarning. This warning signals that a Promise was rejected, and no error handler was attached to it. While seemingly straightforward, pinpointing the exact location of the unhandled promise can be challenging, especially in large, complex applications. Understanding how to find which promises are unhandled in Node.js UnhandledPromiseRejectionWarning is crucial for maintaining application stability and preventing unexpected crashes. This guide provides practical strategies and techniques to effectively diagnose and resolve these issues, ensuring your Node.js applications run smoothly and reliably. We’ll explore various methods, from leveraging Node.js’s built-in debugging tools to implementing custom error handling mechanisms, to help you become proficient at tracking down and fixing unhandled promise rejections.

Understanding Unhandled Promise Rejections

At its core, an unhandled promise rejection occurs when a JavaScript Promise is rejected (meaning an error occurred during its execution), and there’s no .catch() block or rejection handler attached to it to gracefully handle that error. In Node.js, the runtime detects these situations and emits an UnhandledPromiseRejectionWarning to alert developers to the potential issue. Ignoring these warnings can lead to unexpected behavior, application crashes, or data corruption, making it critical to address them promptly. These errors often arise from overlooked error conditions, incorrect Promise chaining, or asynchronous operations that fail silently.

The UnhandledPromiseRejectionWarning is a safeguard. Node.js provides it to ensure developers are aware of potential issues in their asynchronous code. It’s far better to address these warnings early in the development process than to encounter runtime errors in a production environment. Consider these warnings as opportunities to improve your code’s robustness and error handling capabilities. Remember, unhandled rejections can mask underlying problems that, if left unchecked, can lead to more severe consequences down the line. Proper error handling isn’t just about silencing warnings; it’s about building resilient and reliable applications. Node.js documentation provides comprehensive details about handling unhandled rejections.

The key here is proactive error handling. Don’t wait for the warnings to appear; design your asynchronous code with error handling in mind from the start. This includes using .catch() blocks in your Promise chains, implementing try…catch blocks around asynchronous functions, and consistently checking for errors in callbacks. By incorporating these practices, you can significantly reduce the likelihood of encountering UnhandledPromiseRejectionWarning and build more robust applications. This contributes to better software quality and reduces the potential for unforeseen issues in the long run.

Strategies for Locating Unhandled Promises

Pinpointing the exact location of an unhandled promise rejection can be tricky. Fortunately, several strategies can help you track down the offending promise. These range from leveraging Node.js’s built-in debugging tools to implementing custom error handling mechanisms.

  • Utilize the process.on(‘unhandledRejection’, …) event: This allows you to globally catch unhandled rejections and log more detailed information, such as the stack trace, which can help you pinpoint the source of the rejection.
  • Employ async/await with try/catch blocks: Wrapping your asynchronous code in try…catch blocks provides a structured way to handle errors and identify the specific line of code that caused the rejection.

One effective approach is to use the process.on(‘unhandledRejection’, …) event. This allows you to register a global handler that will be invoked whenever an unhandled promise rejection occurs. Within this handler, you can log the rejection reason, the promise object, and, most importantly, the stack trace. The stack trace provides a detailed call stack that shows the sequence of function calls that led to the rejection. By examining the stack trace, you can often identify the exact line of code where the error originated. For example:

process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled Rejection at:', promise, 'reason:', reason); console.error(reason.stack); }); 

Another powerful technique is to use async/await syntax along with try…catch blocks. This approach allows you to write asynchronous code that looks and behaves more like synchronous code, making it easier to reason about and debug. By wrapping your asynchronous operations in try…catch blocks, you can catch any rejections that occur and handle them gracefully. This provides a more localized and controlled way to manage errors compared to relying solely on global unhandled rejection handlers. The featured snippet below illustrates this concept:

Featured Snippet: To effectively manage unhandled promise rejections with async/await, wrap your asynchronous operations within a try…catch block. This allows you to catch any errors that occur during the execution of the Promise and handle them appropriately. The catch block can then log the error, perform cleanup actions, or re-throw the error if necessary. This localized error handling simplifies debugging and prevents unhandled rejections from propagating up the call stack. Using this method, pinpointing the exact origin of an error becomes more straightforward.

Debugging with Node.js Inspector

The Node.js inspector is a powerful debugging tool that allows you to step through your code, inspect variables, and set breakpoints. It’s an invaluable asset when trying to find which promises are unhandled in Node.js UnhandledPromiseRejectionWarning. By attaching the inspector to your Node.js process, you can gain real-time visibility into the execution of your code and identify the exact point where a promise is rejected without being handled.

To use the Node.js inspector, start your Node.js application with the –inspect flag. This will enable the inspector and print a URL to the console that you can open in a Chromium-based browser (like Chrome or Edge). Once connected, you can set breakpoints in your code, step through the execution line by line, and inspect the values of variables at each step. This allows you to trace the flow of execution and identify the exact point where a promise is rejected. You can also use the inspector to pause execution when an exception is thrown, which can be helpful for identifying unhandled promise rejections. The inspector’s console also allows you to evaluate expressions and execute code snippets in real-time, providing a powerful way to experiment and debug your code. For more in depth explanation, see this Node.js debugging guide.

Furthermore, the inspector provides features like conditional breakpoints, which allow you to set breakpoints that only trigger when certain conditions are met. This can be particularly useful when debugging asynchronous code, where the timing of events can be unpredictable. By setting conditional breakpoints based on the state of your promises, you can narrow down the search for unhandled rejections and focus on the specific scenarios where they are likely to occur. The inspector also supports remote debugging, allowing you to debug Node.js applications running on remote servers or in Docker containers. This is especially helpful for debugging production environments where you may not have direct access to the code. This is critical to ensuring a stable application.

Best Practices for Promise Error Handling

Preventing UnhandledPromiseRejectionWarning is always preferable to debugging them after they occur. Implementing robust error handling practices in your Promise-based code is crucial for building resilient and reliable applications. By adopting a proactive approach to error handling, you can minimize the risk of unhandled rejections and ensure that your application gracefully handles unexpected errors. Error handling is critical for maintaining application stability and preventing unexpected crashes due to unhandled promise rejections.

  1. Always attach .catch() handlers to your Promises: This ensures that any rejections are caught and handled appropriately.
  2. Use async/await with try…catch blocks: This provides a structured and readable way to handle errors in asynchronous code.
  3. Implement global unhandled rejection handlers: This provides a safety net for catching any rejections that are not handled locally.

One of the most fundamental best practices is to always attach .catch() handlers to your Promises. Every Promise chain should have a .catch() block at the end to handle any rejections that may occur along the way. This ensures that no rejection goes unhandled and that your application has an opportunity to gracefully recover from errors. Similarly, when using async/await syntax, always wrap your asynchronous operations in try…catch blocks. This provides a structured and readable way to handle errors and prevent unhandled rejections. Ensure error messages are descriptive to aid in debugging.

In addition to local error handling, it’s also a good idea to implement a global unhandled rejection handler using process.on(‘unhandledRejection’, …). This provides a safety net for catching any rejections that are not handled locally. Within the global handler, you can log the rejection reason, the promise object, and the stack trace to help you diagnose the issue. However, it’s important to note that the global handler should not be used as a substitute for proper local error handling. It should only be used as a last resort to catch unexpected rejections that may have slipped through the cracks. Remember to document your error handling strategies.

FAQ: Unhandled Promise Rejections

What causes an UnhandledPromiseRejectionWarning in Node.js?
It occurs when a Promise is rejected, and there is no .catch() handler or rejection handler attached to it to handle the error.
How can I prevent UnhandledPromiseRejectionWarning?
Always attach .catch() handlers to your Promises, use async/await with try...catch blocks, and implement global unhandled rejection handlers.
What information does the process.on('unhandledRejection', ...) event provide?
It provides the rejection reason, the promise object, and the stack trace, which can help you pinpoint the source of the rejection. [Mozilla documentation on promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) can provide even greater understanding.
You now have a solid understanding of how to tackle those pesky UnhandledPromiseRejectionWarning messages in your Node.js applications. By consistently applying these strategies – leveraging debugging tools, implementing robust error handling, and understanding the nuances of asynchronous JavaScript – you'll not only squash those warnings but also build more resilient and reliable code. Don't just silence the warnings; understand and address the underlying issues. Start by reviewing your recent code changes, paying close attention to any asynchronous operations that might be missing error handling. Consider exploring related topics such as asynchronous error handling patterns and advanced debugging techniques to further enhance your skills. Your applications, and your users, will thank you. **Question & Answer :** Node.js from version 7 has async/await syntactic sugar for handling promises and now in my code the following warning comes up quite often:
(node:11057) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: Error: Can't set headers after they are sent. (node:11057) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. 

Unfortunately there’s no reference to the line where the catch is missing. Is there any way to find it without checking every try/catch block?

listen unhandledRejection event of process.

process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); // application specific logging, throwing an error, or other logic here });