61

Can someone expound on the times when it's appropriate in a node.js Express app to throw an error like so:

throw new Error('my error');

or to pass this error on via the callback usually labelled 'next' like so:

next(error);

and could you please explain what each of them will do in the context of an Express app?

for example, here is an express function dealing with URL parameters:

app.param('lineup_id', function (req, res, next, lineup_id) {
        // typically we might sanity check that user_id is of the right format
        if (lineup_id == null) {
            console.log('null lineup_id');
            req.lineup = null;
            return next(new Error("lineup_id is null"));
        }

        var user_id = app.getMainUser()._id;
        var Lineup = app.mongooseModels.LineupModel.getNewLineup(app.system_db(), user_id);
        Lineup.findById(lineup_id, function (err, lineup) {
            if (err) {
                return next(err);
            }
            if (!lineup) {
                console.log('no lineup matched');
                return next(new Error("no lineup matched"));
            }
            req.lineup = lineup;
            return next();
        });
    });

In the line commented "//should I create my own error here?" I could used "throw new Error('xyz')", but what exactly would that do? Why is it usually better to pass the error to the callback 'next'?

Another question is - how do I get "throw new Error('xyz')" to show up in the console as well as the browser when I am in development?

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817

5 Answers5

27

In general express follows the way of passing errors rather than throwing it, for any errors in the program you can pass the error object to 'next', also an error handler needs to be defined so that all the errors passed to 'next' can be handled properly.

http://expressjs.com/en/guide/error-handling.html

empflow
  • 111
  • 2
  • 8
Arjun
  • 577
  • 6
  • 13
  • 3
    What I generally do is to throw the error inside a try catch and call `next(error)` in the catch block – DollarAkshay Jul 23 '21 at 21:06
  • If anyone interested in the English version of this webpage: https://expressjs.com/en/guide/error-handling.html – himanshupareek66 Feb 07 '22 at 14:55
  • I followed the ExpressJS documentation and developed an npmjs library that implements a basic handling for HTTP errors, similar to the restify way. (eg. ```next(new BadRequestError('message here'))```). I hope it be useful. https://www.npmjs.com/package/@acruzjr/express-http-errors ```npm i @acruzjr/express-http-errors``` – Juninho Cruz Feb 27 '22 at 01:46
14

Throwing an error inside a callback doesn't work:

app.get('/', function (req, res) {
  fs.mkdir('.', (err) => {
    if (err) throw err;
  });
});

But calling next works:

app.get('/', function (req, res, next) {
  fs.mkdir('.', (err) => {
    if (err) next(err);
  });
});
pmiguelpinto90
  • 573
  • 9
  • 19
5

Errors that occur in synchronous code inside route handlers and middleware require no extra work. If synchronous code throws an error, then Express will catch and process it. For example:

app.get('/', function (req, res) {
  throw new Error('BROKEN') // Express will catch this on its own.
})
eric_cartman
  • 67
  • 1
  • 3
  • 2
    How do you add a statusCode to this error? `throw new Error('error', 404)` doesn't work. – mcv Apr 20 '20 at 16:04
  • 2
    const err = new Error('Error message'); err.statusCode = 404; throw err; – Mahamat Feb 16 '21 at 08:30
  • Please acknowledge when quoting from external sources (in this case, the [Express docs](http://expressjs.com/en/guide/error-handling.html)) rather than making it look like your own work. – Mitya May 04 '23 at 11:16
4

Express will handle all errors that are thrown in synchronous code. I.e:

app.get('/', function (req, res) {
  throw new Error('My custom thrown Error') // Express will catch this on its own.
})

When an error is thrown inside asynchronous code you, you need to tell express to handle the error by passing it to the next function:

app.get('/', function (req, res, next) {
  Promise.resolve().then(() => {
    throw new Error('My custom thrown Error inside a promise')
  }).catch(err => {
    next(err); // Inside async code you have to pass the error to the next function, else your api will crash
  })
})

And you got to be careful, as soon you declare a function with the async keyword, the content of the function is running asynchronous:

app.get('/', function (req, res) {
  throw new Error('My custom thrown Error') // Express will catch this on its own.
})
app.get('/', async function (req, res, next) {
  throw new Error('My custom thrown Error') // Express will NOT!! catch this on its own, because it is in an asynchronous function
})

If you want to read more, take a look at the docs: https://expressjs.com/en/guide/error-handling.html

Dominik R.
  • 123
  • 5
3

For those who prefer throwing errors, here is a workaround decorator:

export function safeThrow(
    target: object,
    key: string | symbol,
    descriptor: TypedPropertyDescriptor<(req: Request, res: Response, next: NextFunction) => Promise<any>>) {
    const fun = descriptor.value;
    descriptor.value = async function () {
        try {
            await fun.apply(this, arguments);
        } catch (err) {
            arguments[2](err);
        }
    };
}

@safeThrow
private async get(req: Request, res: Response, next: NextFunction) {
  throw { status: 404, message: 'Not supported' }
}
Oleg Khalidov
  • 5,108
  • 1
  • 28
  • 29