Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Node.JS: unhandledRejection with async function calls that are not awaited

Edit: in summary this issue is regarding unhandledRejection in node.js. I didn’t expect a promise that was not awaited (but later fails) to crash the program – because I didn’t realize that unhandledRejection was being thrown & causing node.js to exit. Refreshing my understanding of unhandledRejection I now realize that any promise anywhere in the program that is rejected without a catch() statement will throw unhandledRejection and exit the node.js process on default. Which doesn’t make too much sense to me, but at least I understand why it’s happening.

In the following code example, thisFailsLater initially returns successfully, but then throws an error some time later.

This results in runTest() passing the try/catch and moving on to the next await.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

However, while waiting for the next await call, thisFailsLater then throws an error, which causes Node.JS to exit:

% node t.js 
Throwing error in 2 seconds
thisFailsLater returned successfully
t.js:4
  throw new Error('thrown error in thisFails()')
        ^

Error: thrown error in thisFails()
    at thisFails (t.js:4:9)

This is something I didn’t expect: it seems that an async function can initially return successfully, but then any async function called but not awaited within the function that throws after returning will then crash the Node.JS process.

Am I correct in how this works? And if so, how can I prevent Node.JS from exiting when thisFailsLater() throws 2 seconds after returning successfully? This completely breaks my understanding of how Promises work (can only be resolved or errored once).

Error reproduction:

async function thisFails() {
  console.log('Throwing error in 2 seconds')
  await new Promise((resolve) => setTimeout(resolve, 2e3));
  throw new Error('thrown error in thisFails()')
}

async function thisFailsLater() {
  try {
    // NOTE: intentionally NOT awaiting this call here.
    thisFails()
  } catch (err) {
    console.log('thisFailsLater caught error', err)
  }
}

async function runTest() {
  try {
    await thisFailsLater()
  } catch (err) {
    console.error('runTest caught error', err)
  }
  console.log('thisFailsLater returned successfully')
  await new Promise((resolve) => setTimeout(resolve, 3e3));
}

runTest().then(() => {
  process.exit(0)
}).catch((err) => {
  // NOTE: the error that Node.JS crashes with is NOT logged here!
  console.error('Caught error in main()', err)
  process.exit(1)
})

>Solution :

It seems that an async function can initially return successfully, but then any async function called but not awaited within the function that throws after returning will then crash the Node.JS process.

Am I correct in how this works?

Yes. But this is not unique to async functions – any function can do that in node.js:

function failLater() {
    setTimeout(() => {
        throw new Error("crash!");
    }, 1000);
    return "success"
}

And if so, how can I prevent Node.JS from exiting when thisFailsLater() throws 2 seconds after returning successfully?

Just don’t do that.™

Do not let functions cause exceptions asynchronously.

To prevent nodejs from exiting, you can hook on the global error and unhandledrejection events, but those are meant for logging – your application already has suffered from an unrecoverable error.

This completely breaks my understanding of how Promises work (can only be resolved or errored once).

It’s not related to promises, the promise does settle only once, when the body of the async function concludes evaluating. The thisFails() is a second, separate promise – independent from the flow of execution since you didn’t await it.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading