catch error of “toplevel” app.use-middlewear in router error handler

In the docs (http://expressjs.com/guide/error-handling.html) I read “Define error-handling middleware like other middleware, except with four arguments instead of three, specifically with the signature (err, req, res, next))” and “next(err) will skip all remaining handlers in the chain except for those that are set up to handle errors as described in the next section”.

However, express doesn’t behave as I expect from what I read in the docs. This…

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

// generate error on every request
app.use(function(req, res, next) {
  next(new Error('Always, I want to be with you'));
});

// route /test with own error handler
var testRouter = express.Router();
testRouter.use(function(err, req, res, next) {
  res.send('testRouter error handler: ' + err.message); // <-- never called, even for requests to /test
});
app.use('/test', testRouter);

// default error handler
app.use(function(err, req, res, next) {
  res.send('default error handler: ' + err.message);
});

module.exports = app;

…will always return default error handler: Always, I want to be with you, regardless of the requested resource. If next(err) would really “skip all remaining handlers in the chain except for those that are set up to handle errors”, the result for requests to /test should be testRouter error handler: Always, I want to be with you.

I stumbled upon this when trying to catch errors from a “globally” applied bodyParser in a router which handles API requests (because I need to have a different error output there).

Author: Fantashit

1 thought on “catch error of “toplevel” app.use-middlewear in router error handler

  1. they don’t catch errors that occur in other middleware outside of that router (that’s what we’re talking about, isn’t it? 🙂 ). Requests to /api/v1.0 shall be processed by “application level” middleware first (e.g. bodyParser), which might produce an error

    Ah, ha! Sorry, I totally forgot that from your initial post 🙂 Yes, indeed, those errors would not climb into your sub router, by bad 🙂

    To me, the way it works is basically just like trycatch:

    try {
      // main router
      parseBody()
    
      try {
        // sub router
        doThings()
      } catch (e) {
        // error handlers in your sub router--they wouldn't catch parseBody(), just like JS itself
      }
    } catch (e) {
      // error handlers on your main router
      // of course this catches all fall-through errors, just like JS itself
    }

    Another thing you can try is, if possible, to move body parsing closer to where you’re going to actually use it, such that you are not parsing bodies to 404 routes or unauthenticated resources. https://github.com/expressjs/body-parser#express-route-specific provides a basic example of this pattern.

Comments are closed.