skip to Main Content

After searching on SO, I could not find an answer to this problem. All of the questions I saw, the error was still being caught. I’m having the inverse problem. No matter how I refactor the following code, I am STILL not able to catch the error.

I hope I’m just overlooking something or doing something wrong.

process.on("uncaughtException", uncaughtExceptionListener)

start().catch(console.error)

async function start() {
  try {
    await queue.connect()
  } catch (err) {
    return console.error('Some Error:', err.message)
  }
}

// queue.connect in class
async function connect() {
  try {
    // The next line is where the error originates
    await client.connect()
    return console.log('Never makes it here')
  } catch (err) {
    // Never makes it here either
    return console.error('[client] Connection failed!')
  }
}

Output:

node:internal/process/promises:391
    triggerUncaughtException(err, true /* fromPromise */);
    ^

Error: connect ECONNREFUSED 127.0.0.1:6090

I’ve rewritten connect() as simple as possible in multiple different ways:

function connect() {
  const p2 = new Promise((resolve, reject) => {
    client.connect().then(resolve).catch(reject)
  })

  p2.then(n => {
    // ...
  }).catch(e => {
    console.log('Never makes it here')
  })

  return p2
}

And even more simply:

async connect() {
  try {
    // The next line is where the error originates
    await client.connect()
  } catch (err) {
    return console.log('Never makes it here')
  }
}

Replacing await client.connect() with throw new Error('client.connect() simulation')
Everything works as it should. What is client.connect() doing, where the exception can not be caught?

Going as far as encapsulating the actual .connect method, the exception still happens and node crashes. Example:

client.connect().then(() => {}).catch(err => console.error('We never make it here'))

Version: (Although still happens on latest node version)

$ node --version
v20.18.0

Client in question: bee-queue
bee-queue.connect function

3

Answers


  1. Chosen as BEST ANSWER

    Solved. The issue was not in my code. The issue was upstream in the bee-queue library. The promise was not being caught and rejected to the downstream promise chain.

    See this PR for more info: https://github.com/bee-queue/bee-queue/pull/878


  2. The thing is, async/await offers a way to write a chain of promises/then (of even just callbacks) with a simple writing, as if all asynchronous operations were synchronous. But, still, under the hood, they are still asynchronous.

    Just an over simplification of your example

    async function connect(){
        throw "failed connect";
    }
    
    async function start(){
        await connect();
        dosomethingelse();
    }
    
    start();
    

    It is important to understand, that this is the equivalent of

    function start(){
         connect().then(function(){
             dosomethingelse();
         })
    }
    

    It is a wonderful improvement to JS, since sometimes you may have a sequence of 10 asynchronous operations to perform. So it is convenient to write them in sequence with just a plain ; separator, as if it was a simple connect(); dosomething();, when in reality is connect(continuation); end this function, continuation being that do something.
    But, still, it is a bunch of promises and then

    So, if you add a try/catch block now

    async function connect(){
        throw "failed connect";
    }
    
    async function start(){
        try{
            await connect();
        }catch(e){
            console.log("catch", e);
        }
    }
    

    Well, it is still in reality

        try{
            connect().then(continuation)
        }catch(e){
            ...
        }
    

    the try englobes only the calls to asynchronous connect

    So a little bit like

    try{
        setTimeout(trytoconnect, 1000);
    }catch(e){
    }
    

    wouldn’t catch anything happening in trytoconnect, your try/catch has no reason to catch what happens in your connect (unless the error happens in the creation of the promise itself, not in its execution)

    As for a solution, you can find one here

    function okOrError(promise){
        return promise.then((arg) => {return {ok: arg}}).catch((arg) => {return {error: arg}});
    }
    
    async function connect(){
        if(Math.random()<0.5) return "success";
        throw "failed connect";
    }
    
    async function start(){
        let x=await okOrError(connect())
        if(x.error) throw x.error;
        console.log(x.ok);
    }
    
    
    start();
    
    Login or Signup to reply.
  3. Let me say this… You’re not doing it right…

    async functions always will return a promise. Then you must use .then() and/or .catch() on the async function call, even if you await for the fulfillment. try/catch will never get the error because they run outside of this block context.

    Here’s a working example:

    // Let's say you have an async function...
    async function doSomething ()
    {
      // And it do something that causes an error.
      window.inexistentMethod();
    }
    
    // If you want to catch the error...
    async function doTest()
    {
      const value = await doSomething()
        .then
        (
          result =>
          {
            console.log('Result:', result)
            
            // What will go into `value`.
            return result ?? true;
          }
        )
        .catch
        (
          error =>
          {
            console.warn('Error:', error.message);
            
            // What will go into `value`.
            return false;
          }
        );
      
      console.log('Final value:', value);
    }
    
    // TEST THE ERROR:
    doTest();

    NOTE that .then() and .catch() both return a different promise than the one they’re called upon. So, in the above example, first is parsed doSomething() that returns a promise, then .then() that returns another promise that fulfills if there’s no error in doSomething() and .then(), then .catch() that returns another promise that fulfills if doSomething() and .then() produces no error or call the callback on .catch if there’s any error and then returns what the callback returned. Only then, the await will retrieve the promise return value.

    There are those two other answers I gave to other questions that shows how to handle unhandled errors that may come from setTimeout, events and other async sources:

    https://stackoverflow.com/a/79189671/2804429

    https://stackoverflow.com/a/79184566/2804429

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search