Solved

One failed request takes down my whole Express server

Asked by Samuel Okafor · 456 views · 2 replies

Samuel Okafor8 messages

If the database is briefly unreachable, one request fails and then the entire Node process exits:

[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 route is just:

app.get("/users/:id", async (req, res) => {
  const user = await db.findUser(req.params.id);
  res.json(user);
});

Shouldn't Express catch errors in route handlers?

2 replies

Kenji MoritaSolution

Two things are combining here.

Node: since Node 15, an unhandled promise rejection crashes the process by default. Older versions only printed a warning, which is why a lot of tutorials never mention it.

Express 4: it catches errors thrown synchronously in a handler, but it does not look at the promise an async handler returns. When await db.findUser() rejects, nobody handles that promise, so Node's default kicks in.

The cleanest fix is upgrading to Express 5, which passes a rejected promise from a handler to your error middleware automatically. On Express 4, catch it yourself and hand it to next:

app.get("/users/:id", async (req, res, next) => {
  try {
    const user = await db.findUser(req.params.id);
    res.json(user);
  } catch (err) {
    next(err);
  }
});

Either way, add an error handler (four arguments) at the end so the client gets a 500 response instead of a dropped connection.

Link
Samuel Okafor

Upgraded to Express 5, deleted the try/catch blocks I had started adding everywhere, and the server now returns a 500 and stays up. Much better.

Link