Error Handling Middleware in Express

Jul 18, 2019

Express' error handling middleware helps you handle errors without repeating yourself. Suppose you handle errors directly in your Express route handler:

app.put('/User/:id', async function(req, res) {
  let user;
  try {
    user = await User.findOneAndUpdate({ _id: req.params.id }, req.body);
  } catch (err) {
    return res.status(err.status || 500).json({ message: err.message });
  }
  return res.json({ user });
});

The above code works, but, if you have hundreds of endpoints, your error handling logic becomes unmaintainable because it is duplicated hundreds of times. Enter error handling middleware.

Introducing Error Handling Middleware

Express looks at the number of arguments a middleware function takes to determine what type of middleware it is. A middleware function that takes 4 arguments is defined as error handling middleware.

const app = require('express')();

app.get('*', function routeHandler() {
  throw new Error('Oops!');
});

// Your function  **must** take 4 parameters for Express to consider it
// error handling middleware.
app.use((err, req, res, next) => {
  res.status(500).json({ message: err.message });
});      

Express automatically handles synchronous errors for you, like the routeHandler() function above. Express does not handle asynchronous errors though. If you have an asynchronous error, like one in an async function, you need to call next().

const app = require('express')();

app.get('*', async function asyncRouteHandler(req, res, next) {
  try {
    throw new Error('Oops!');
  } catch (err) {
    // The `next()` function tells Express to go to the next middleware
    // in the chain. Express doesn't handle async errors, so you need to
    // report errors by calling `next()`.
    return next(err);
  }
});

app.use((err, req, res, next) => {
  res.status(500).json({ message: err.message });
});      

More Express Tutorials