

Node.js error handling - beastmcbeast
http://snmaynard.com/2012/12/21/node-error-handling/

======
STRML
Unfortunately error handling in Node.js is a total mess.

As with most new technologies there are few standards and whatever standards
there are are subject to change. It was only a short time ago that many
Node.js libs were being produced with promises.

The most common style I see today is this callback style:

    
    
      doAsyncCall(function(err, result){
        if(err){ // handle err }
      });
    

Unfortunately this is prone to error. When writing any sort of asynchronous
function - that is, 'doAsyncCall' itself, you need to write it in the
following way:

    
    
      function doAsyncCall(cb){
        // .. do some async stuff
        if(// error has been thrown){
          callback(err);
        } else {
          callback(null /* this is where confusion happens */, result);
        }
      }
    

When writing such code you need to be very consistent and very aware of what
error handling style is being used. It can be jarring for some to
intentionally pass null as the first argument.

I am personally a fan of the `if(result typeof Error)` style but it is not
common. Many frequently used libraries, like Mongoose, use the (err, result)
style.

Because any async call can theoretically fail, and because you need to catch
every potential error, it is common for starting programmers (and even
experienced ones) to miss an edge case or two. I advocate using upstart or a
similar scheme to make sure your Node server stays alive, even if you happen
to have missed an error somewhere.

~~~
coryvirok
One of the things I love about node.js is that it forces you to come up with a
style and stick with it for things like this. At <http://ratchet.io> our API
servers are written in node.js and we chose the foo(err, callback) method.

I personally love this style even though it makes you write more boiler-plate
code, it forces you to write exception-safe code from the start. Also, it
forces a structure on all of your code that you can instantly recognize as
missing if someone forgets to check for err in the callback.

If you can stick with the style, it's fairly difficult to write code that
doesn't deal with errors gracefully.

~~~
kevingadd
How do you deal with code where the author forgot to handle all of the failure
cases and invoke the callback?

~~~
STRML
To be honest... since you can't try/catch, you can't do much.

You can catch the exception with something like this:

    
    
      process.on('uncaughtException', function (err) {
        console.err("Uncaught exception: " + err);
        console.err("Uncaught exception stack: " + err.stack);
      });
    

I use the built-in clustering module (implementation is very simple) so a
simple worker crash will result in the error being logged & the worker being
restarted.

That's about the best you can do, unfortunately. You could always monkey patch
the lib if you can figure out where it's crashing.

I recommend Longjohn(<https://github.com/mattinsler/longjohn>) for these sorts
of situations; the extra stack trace lines become invaluable.

------
PhrosTT
I actually just wrote a Node + Express + Backbone error handling system today.

I've been staying sane through the use of the 'Q' promise package
(<https://github.com/kriskowal/q>). For example, in the below code chunk any
errors thrown in makeEmailConfirmation or sendEmailConfirmation will land in
the .fail() catch block.

I believe using a promise system is the only way to avoid callback hell.

    
    
      var deferred = Q.defer();
    
      ...  
      
      Storage.CustomLinks.makeEmailConfirmationLink(user)
      .then(function(link) {
        return Email.sendEmailConfirmation(user, link);
      })
      .then(function(result) {
        deferred.resolve(result);
      })
      .fail(function(err) {
        deferred.reject(new ServerError(err));
      })
      .end();
    
      ...
    
      return deferred.promise;

~~~
beefsack
I've recently written an application extensively using Q, and was very pleased
at how clean my code ended up being. Particularly in comparison to how node.js
code tends to end up looking once your callback pyramids start to grow.

------
scriby
Will these examples protect you from thrown exceptions? Null reference
exception? Oops, your callback isn't getting called -- and you're probably
leaking resources or leaving things in an inconsistent state.

So the recommendation is to restart the process - but let's not forget that
hundreds+ of other requests could currently be in the pipeline - are we just
going to abort those too?

Ok, we'll clearly the solution is to wrap all our callbacks with try/catch!
Shoot me now...

For large, sprawling applications used to support a business, something like
<https://github.com/scriby/asyncblock> can resolve most of the headaches with
async code, including error handling. It's worked out well for my team at
work, which is building a "very large" node application.

Disclaimer: Asyncblock is my pet project.

------
chrisringrose
Finally a good explanation of error handling in node.js. Cheers!

------
aneth4
Seems like promises (e.g. Q) use a other sort of error handling similar to
domains, but win a cleaner syntax the addition of the promises functionality.

~~~
aneth4
Wow, I should proof read on my iphone.

------
benatkin
There seems to be an error in the final code snippet. Instead of d.intercept
it should be mainDomain.intercept. Here's the original example:
<http://nodejs.org/api/domain.html#domain_example_1>

~~~
beastmcbeast
Apologies for that, I've updated the example. Thanks for pointing it out.

