1

Let's suppose I want to use an async function foo from an external library, which calls another async function bar that throws an error that foo does not handle:

// External library code (non-modifiable)

async function bar(){
  throw Error("Error example");
}

async function foo() {
  bar(); // <-- Note this is not awaited!!
}

If in my code I want to use foo, is there any way I can handle the error thrown by bar? This does not work, as foo does not await for bar:

// My code

async function myMain(){
  try {
    await foo();
  } catch (error) {
    console.log("Error captured in myMain:", error.message);
  }
}

My bet is that the foo function not awaiting bar it's a bug in the external library. But until it's fixed, do I have any way to handle the error that it throws?

The code is inside an AWS Lambda, which causes 500 errors when it has unhandled exceptions. I need a way to handle the errors "gracefully" to avoid that.

I do not know why the external library calls the function that throws the error without properly handling it. But as I am forced to use it and I cannot modify its code, I think that using undhandledRejection may be the only course of action. Although I do not like it. I want to handle that function's specific unhandled errors, but let the other ones pass, as they might be bugs in my code I would like to detect.

11
  • Why is foo async and why do you await it? The external library seems to contain multiple bugs. Commented Mar 31 at 11:58
  • @jabaa This is a simplified example. foo represents a function of an external library that does multiple things. But, because of a bug I guess, it does not always handle all the errors that can happen. Commented Mar 31 at 12:03
  • 2
    @Yogi In those questions, if I understand them correctly, the async functions that may throw errors are "awaited". So although they are not inside try-catch clauses, they are inside the promise chain. In my case, the function that throws the error is not awaited nor is part or a .then().catch() chain (I think because of a bug on their part). Commented Mar 31 at 12:11
  • 1
    Either you've oversimplified the code or you can't handle the error. bar() returns a promise that's discarded and rejected. I would call this a bug in the external library. Commented Mar 31 at 12:13
  • 1
    "My bet is that the foo function not awaiting bar is a bug in the external library." - yes, absolutely. Make them fix it. There are some workarounds, but none of them good. Commented Mar 31 at 12:56

2 Answers 2

1

If you can't get bar() fixed, a workaround is to wrap foo with something that sets a global unhandledRejection handler, calls foo, and then removes the handler.

This will catch errors in foo's call chain (and unfortunately, any other unhandled rejections that happen during the execution of foo). Something like this:

// OP's code
async function bar() {
  throw Error("Error example");
}

async function foo() {
  bar(); // no await
}

// wrap foo:
async function safeFoo(params) {
  return new Promise((resolve, reject) => {
    const fooRejection = error => {
      process.off('unhandledRejection', fooRejection);
      reject(error);
    };

    process.on('unhandledRejection', fooRejection);

    foo()
      .then(() => new Promise(res => setImmediate(res)))
      // skip a turn of the event loop so unhandledRejection can be emitted
      .then(resolve).catch(reject)
      .finally(() => {
        process.off('unhandledRejection', fooRejection);
      });
  });
}

async function myMain() {
  try {
    await safeFoo();
  } catch (error) {
    console.log("Error captured in myMain:", error.message);
  }
}

myMain();
Sign up to request clarification or add additional context in comments.

Comments

0

There is no way to fix this inside myMain() alone without modifying foo() or bar() directly, because the error is already unhandled at the foo() level.

  • The best fix is modifying foo(). (awaiting bar())
async function foo() {
    await bar()
}
  • If modifying foo() is not allowed, you must handle it globally

    Handling globally:

process.on('unhandledRejection', (error) => {
    console.log("Caught an unhandled rejection:", error.message);
});

2 Comments

The second snippet depends on the runtime environment. It doesn't work in a browser.
Also, the second snippet, if ran on Node, will catch other promise rejections, not just ones coming from foo/bar/the external library. And even then, it'd mostly silence the issue, it won't necessarily remove it. If bar() is doing an async operation and it fails, just turning a blind eye to it isn't exactly safe. Consider - if bar() is adding to a database, then some data might not be there after foo() finishes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.