DEV Community

Lars-Erik Bruce
Lars-Erik Bruce

Posted on

Don't feed async functions to express handlers

Express does not support async handlers. I have witnessed an application who restarted every time the async function threw an error. This was on Node 16.

When we updated to Node 20, the whole application froze instead. After too many hours with debugging, I uncovered that the issue was async functions in express.

Running express on node 20, we weren't able to even see anyhing in the log. With node 16, the application crashed, with this error message:

node:internal/process/promises:279
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: 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(). The promise rejected with the reason "AxiosError: Request failed with status code 400".] {
code: 'ERR_UNHANDLED_REJECTION'
}
Enter fullscreen mode Exit fullscreen mode

So what happened was that inside an express route async function, we did a subsequent call to another API with Axios, that failed with a status code 400. But since express doesn't support async functions, it couldn't catch the error and handle it.

How to fix it? Call your async function as a promise!

Let's say you have the following route defined:

app.get('/api/some/endpoint', someAsyncHandler);
Enter fullscreen mode Exit fullscreen mode

You can here write an inplace wrapper for the async handler:

app.get('/api/some/endpoint', function someAsyncHandlerWrapper(req, res) {
  someAsyncHandler(req, res).catch(function errorHandler(error) {
    logger('Failed to handle this API endpoint.', e.message);
    res.sendStatus(500);
  }
});
Enter fullscreen mode Exit fullscreen mode

So, use the async function as a promise (since async/await is just syntactic sugar for promises either way), and send a response code of 500 back to the client!

Top comments (0)