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 });
});      

Want to become your team's Express expert? There's no better way to really grok a framework than to write your own clone from scratch. In 15 concise pages, this tutorial walks you through how to write a simplified clone of Express called Espresso. Get your copy!

Espresso supports:
  • Route handlers, like `app.get()` and `app.post()`
  • Express-compatible middleware, like `app.use(require('cors')())`
  • Express 4.0 style subrouters
As a bonus, Espresso also supports async functions, unlike Express.

Get the tutorial and master Express today!

Did you find this tutorial useful? Say thanks by starring our repo on GitHub!

More Express Tutorials