Search code examples
node.jses6-promise

UnhandledPromiseRejectionWarning followed by PromiseRejectionHandledWarning


The following code gives an UnhandledPromiseRejectionWarning for p2, despite errors on p2 being explicitly handled.

function syncFunctionReturnsPromise(val)
{
  return new Promise((r,x)=> {
    setTimeout(()=> {
      if (val) { 
        r('ok');
      } else {
        x('not ok');
      }
    }, val?1000:500);
  });
}

async function test(){
  let p1 = syncFunctionReturnsPromise(true);
  let p2 = syncFunctionReturnsPromise(false); 
  await p1.catch(ex => console.warn('warning:', ex));  //errors in these 2 promises
  await p2.catch(ex => console.warn('warning:', ex));  //are not the end of the world
  console.log('doOtherStuff');
}
test();

The output looks like this:

(node:9056) UnhandledPromiseRejectionWarning: not ok
(node:9056) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:9056) [DEP0018] 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.
warning: not ok
doOtherStuff
(node:9056) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)

It is not immediately obvious to me why this should be


Solution

  • So this is because the first await waits synchronously before the handler is attached to p2. But p2 fails before p1 completes.

    So node detects that p2 failed without any error handling.

    N.B. In later versions of node this may cause the program to terminate, rather than just a warning.

    The fix is to attach the handlers before awaiting

    async function test(){
      let p1 = syncFunctionReturnsPromise(true);
      let p2 = syncFunctionReturnsPromise(false); 
      p1 = p1.catch(ex => console.warn('warning:', ex));  //errors in these 2 promises
      p2 = p2.catch(ex => console.warn('warning:', ex));  //are not the end of the world
    
      await p1;
      await p2;
      console.log('doOtherStuff');
    }
    

    Obviously you could inline that on the declaration although in my realworld code its neater as separate lines.