'Express not catching exception in middleware

I'm attempting to use middleware to catch exceptions in routes.

Expected Result:

When an error is thrown in a route I expect it to be caught by the middleware so I can log the error and return a generic response.

Actual Result:

When an error is thrown in the route the middleware is never reached. An Error and stacktrace is printed to the console and the browser displays Internal Server Error. The except thrown:

> NODE_ENV=production node api/server.js

Listening on port 8080!
Error: Error in /invite route
    at app.get (/Users/bughunter/Projects/ooberoo/lander/api/server.js:42:8)
    at Layer.handle [as handle_request] (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/layer.js:95:5)
    at /Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/index.js:281:22
    at Function.process_params (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/index.js:335:12)
    at next (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/index.js:275:10)
    at Layer.handle [as handle_request] (/Users/bughunter/Projects/ooberoo/lander/node_modules/express/lib/router/layer.js:91:12)

Application is ran from npm start script:

"start": "NODE_ENV=production node api/server.js",

My code is below:

const express = require('express');
const path = require('path');
const winston = require('winston');
require('winston-daily-rotate-file');

// Are we production or development?
const env = process.env.NODE_ENV || 'development';

// Express
const app = express();

// Logger
const logger = new (winston.Logger)({
  transports: [ 
    new (winston.transports.DailyRotateFile)({
      filename: path.resolve(__dirname, '../logs/app.log'),
      datePattern: 'yyyy-MM-dd.',
      prepend: true,
      level: process.env.ENV === 'development' ? 'debug' : 'info'
    })
   ]
});

// Static files
app.use(express.static(path.resolve(__dirname, 'static')));

// Generic error middleware
app.use(function(error, req, res, next) {
  logger.log('error', error);
  res.status(500);
  res.setHeader('Content-Type', 'application/json');
  res.json({ error: 'Failed to process request' });
});

// Homepage
app.get('/', (req, res) =>
  res.sendFile(path.resolve(__dirname, './static/index.html'))
);

// Invite signup
app.get('/invite', (req, res, next) => {
  next(new Error('Error in /invite route'));
});

// Redirect to home if no route found
app.get('*', (req, res) =>
  res.redirect('/')
);

app.listen(8080, () =>
  console.log('Listening on port 8080!')
);

I'm doing what it says in the documentation yet it doesn't appear to work. Any advice here?



Solution 1:[1]

Error middleware must be declared in the last, after all other middleware and routes:

app.get('/', (req, res) => ...

app.get('/invite', (req, res, next) => ...

app.get('*', (req, res) => ...

app.use((error, req, res, next) => { ... // <= declare error middleware here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 M4C4R