24

I am beginning to work with Express JS and have run into an issue. I can't seem to figure out the proper way to handle errors.

For example, I have a web services API that serves an object called "event". I'd like to return a simple string of "cannot find event" when a user submits an event id that isn't found. Here is how I'm currently structuring my code:

app.get('/event/:id', function(req, res, next) {
    if (req.params.id != 1) {
        next(new Error('cannot find event ' + req.params.id));
    }

    req.send('event found!');
});

When I submit an id other than 1, Node crashes with the following output:

http.js:527
   throw new Error("Can't set headers after they are sent.");
         ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/usr/local/kayak/node_modules/express/node_modules/connect/lib/patch.js:62:20)
    at /usr/local/kayak/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js:72:19
    at [object Object].<anonymous> (fs.js:107:5)
    at [object Object].emit (events.js:61:17)
    at afterRead (fs.js:878:12)
    at wrapper (fs.js:245:17)

From what I can tell by using the node.js debugger, execution of the block of code continues after next() is called, meaning that req.send('event found!') tries to run. I don't want this to happen.

The only workaround that I've found is to simply throw a new Error() instead of "next-ing" it, but this results in a default Express HTML error page being generated. I'd like a little more control than that.

I have taken the time to read over the error handling section of the Express documentation, but I couldn't make sense of it.

3 Answers 3

35

You'll want to check out Express Error Handling. From there:

app.param('userId', function(req, res, next, id) {
    User.get(id, function(err, user) {
        if (err) return next(err);
        if (!user) return next(new Error('failed to find user'));
        req.user = user;
        next();
    });
});

The sweetspot that you are missing is the return next(...)

Sign up to request clarification or add additional context in comments.

Comments

18

That's because you're doing it wrong: you already threw an Error (which will be processed by Express and return a 500 - Error page for the user or something like that) but you are also trying to send your own response to the client: res.send('event found!');

You should really check out the Express guide about Error Handling here: http://expressjs.com/guide/error-handling.html

What I would do in your example is:

function NotFound(msg){
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
} 

app.get('/event/:id', function(req, res, next){
  if (req.params.id != 1) {
    throw new NotFound('Cannot find event ' + req.params.id);
  } else {
    res.send('event found!');
  }
});

app.error(function(err, req, res, next){
    if (err instanceof NotFound) {
        res.render('404.ejs');
    } else {
        next(err);
    }
});

4 Comments

That express documentation in the link is pretty poor though. It doesn't even mention how you are supposed to properly throw an error, or which version of express its valid for.
That's the link for Express 3.x, if you want to know more about error handling in 2.x checkout this link: expressjs.com/2x/guide.html#error-handling
Oh, the irony: the error handler link in the answer returns a GitHub 404. This is the current active link: expressjs.com/guide/error-handling.html
It should be res.send, not req.send
10

You have a couple of problems in your code:

  • When responding to the client, you need to use the response object (res rather than req).

  • When sending an error to next, you should return, so the rest of the function doesn't run.

Here's your code after fixing those errors:

app.get('/event/:id', function(req, res, next) {
    if (req.params.id != 1) {
        return next(new Error('cannot find event ' + req.params.id));
    }

    res.send('event found!'); // use res.send (NOT req.send)
}); 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.