Error Handling in Node.js[source]

xml
<glacius:metadata>
    <title>Error Handling in Node.js</title>
    <description>Different methods of handling errors in Node.js</description>
    <category>Legacy blog posts</category>
    <category>Programming</category>
    <category>JavaScript</category>
    <category>Node.js</category>
</glacius:metadata>
<glacius:macro name="legacy blargh banner">
    <properties>
        <originalUrl>https://tmont.com/blargh/2014/9/error-handling-in-nodejs</originalUrl>
        <originalDate>2014-09-29T07:25:30.000Z</originalDate>
    </properties>
</glacius:macro>
<p>
  Error handling in Node is kind of weird. And by "kind of weird", I mean
  "different than other languages". The semantics of which I shan't get into,
  but it is my opinion that Node was designed&#x2026; oddly. At least in terms of
  error handling. There are several non-obvious ways in which an error can
  bubble up or otherwise make your program crash, so here's a brief-ish rundown
  of what to look out for. And how to not do things.
</p>
<h3><code>try</code>, <code>catch</code> and <code>throw</code></h3>
  
<p>
  This is the easy one. Except for the parts where it's not easy. Those are hard.
</p>
  
<p>
  The normal Java/C&#x266f;/C++/etc. way of handling errors is via the familiar 
  <code>try..catch</code> construct. It behaves like you would expect:
</p>
<glacius:code lang="javascript"><![CDATA[
try {
  var json = JSON.parse('nope');
} catch (e) {
  console.log(e); //[SyntaxError: Unexpected token o]
}
]]></glacius:code>
<p>
  <code>JSON.parse</code> is a synchronous function, and therefore it <code>throw</code>s
  errors. That's important to remember. You should <strong>never, never, never, ever throw
  an exception from asynchronous code. Ever. Srsly.</strong> 
</p>
<h3><code>error</code> events</h3>
<p>
  <code>error</code> events are kind of stupid. They are a "special" event within Node, and they're
  "special" behavior is that if an <code>error</code> event is emitted without any
  listeners, it crashes the program. Let me repeat that, because repeating things
  is something you do when writing to help emphasize something. Or so my high school
  English teachers taught me.
</p>
<p class="text-center">
  <strong><code>error</code> events without listeners crash programs.</strong>
</p>
<p>
  There are no exceptions to this rule, and you can't get around it. Except by listening for
  <code>error</code> event. They are very similar to checked exceptions in Java, so those
  of you who sold your soul to the <code>AbstractStrategyFactoryFactory</code> can rest
  easy, as this paradigm should be familiar to you already.
</p>
<p>
  Now, normally, this isn't a huge problem, as it's 
  <a href="https://nodejs.org/api/events.html#error-events">documented</a> 
  and standardized, so if you care about something emitting an error and want it to not
  crash your program, you can add a listener and handle it yourself. But it's not
  so easy.
</p>
<p>
  It's not easy because it's turtles all the way down. Many userland libraries
  often do some sort of networking, e.g. connecting to a database. This means
  it has to open a socket. Usually that's all abstracted so that the library is
  easy to use. Often it's the reason for the library. Abstractions are supposed
  to make things easy (and why <code>FactoryFactory</code>s seem to be so
  abundant).
</p>
<p>
  So, now you're connecting to your super awesome NoSQL CouchiakooseandradisDB
  database using some random dude's library, which happens to abstract a socket
  connection. But is that random dude's library handling the 
  <a href="https://nodejs.org/api/events.html#error-events"><code>error</code>
  event</a>? If not, you'll need to dig through that dude's probably well-tested
  and intelligently-factored code to figure it out. And if it isn't handled,
  then you'll have to figure out how to get a hold of the underlying socket
  connection and handle the error yourself. Which kind of defeats the purpose
  of an abstraction. I assure you this has happened to me before. It's rather
  annoying.
</p>
<p>
  The point is, <code>error</code> events can bite you in the ass, because
  they're hard to pinpoint, the stack trace isn't always useful and they
  crash your program for seemingly no reason. Be careful and be aware.
</p>
<h3>Asynchronous errors</h3>
<p>
  Now the real fun. Node is all about those non-blocking system calls. It's
  what makes it semi-awesome. Or, at the very least, it's what makes it
  different. Depending on how angry you are at random dudes, it might
  be the worst thing since the <code>goto</code> statement.
</p>
<p>
  First, let's distinguish between "asynchronous" and "functions that
  return stuff via callback". <strong>Asynchronous</strong> means it's
  literally not blocking execution. When you call an asynchronous function,
  it's going off to do something and meanwhile, the rest of your program
  is executing until that other thing finishes. The act of passing around
  a callback function does not mean that it is asynchronous. If you can
  remember this fact, you'll have a leg up on many random dudes. But not
  in that way, pervert.
</p>
<p>
  The Node convention for passing errors/results in asynchronous functions
  is to pass a callback function as the last argument which takes two
  arguments: an <code>err</code> and a <code>result</code>. The <code>err</code>
  is an error, and if it's truthy, that means something broke.
</p>
<glacius:code lang="javascript"><![CDATA[
fs.stat('/nonexistent/file', function(err, stat) {
  if (err) {
    console.error(err);
    return;
  }
  // do something with the stat object
});
]]></glacius:code>
<p>
  And that's pretty much it. Always remember to handle your errors. Oftentimes
  the <code>result</code> will be <code>null</code> or simply undefined if an error
  occurs. Oh yeah. One other thing. 
  <strong style="text-transform: uppercase">Don't ever mix <code>try..catch</code>
    idioms with callback idioms</strong>. I'll hate you forever if you do. And it's
  bad practice and very confusing, and your stack trace will not be what you think
  it should be.
</p>
<p>
  The only time an asynchronous function (or one that returns its result via a callback)
  should throw an error is if the arguments are bad. Those are programmer errors (e.g.
  compile-time errors) and should be fixed by a programmer. For example, if a function
  expects an object but you pass it a string, it's okay if it throws an exception in 
  that case.
</p>
<glacius:code lang="javascript"><![CDATA[
function asyncSomething(someObject, callback) {
  // okay to throw an exception in this case, although just passing back an error
  // in the callback is totally reasonable as well
  if (typeof(someObject) !== 'object') {
    throw new Error('First argument should be an object');
  }
}
]]></glacius:code>
<h3>A seemingly common error</h3>
<p>
  I've noticed that several well-known and well-used libraries (node-redis and
  mongoose, specifically) fall into this trap of poor error handling. There are
  probably others as well, but those are the two where I've noticed this.
</p>
<p>
  Basically, they have a function definition like so:
</p>
<glacius:code lang="javascript"><![CDATA[
function doSomething(callback) {
  //do something asynchronously, and then...
  try {
    callback();
  } catch (e) {
    this.emit('error', e);
  }
}
]]></glacius:code>
<p>
  Can you spot the problem?
</p>
<p>
  The problem is that it's attempting to <code>catch</code> an error
  that occurs <em>outside of its scope</em>, and then captures that
  error and emits it as if it was an error that occurred inside of
  the library. The following code sample should demonstrate why that is
  bad:
</p>
<glacius:code lang="javascript"><![CDATA[
doSomething(function(err) {
  // ReferenceError: foo is not defined, i.e. programmer error
  // this should crash the program, as it needs to fixed by a programmer
  foo; 
});
]]></glacius:code>
<p>
  What happens in this situation? Suppose the library that has the
  <code>doSomething</code> function was not super important to your
  application, and you don't really care if it <code>error</code>'d. So that means
  you'll be handling the <code>error</code> event, logging it, and
  ignoring it. What happens when the above code is executed? Will the
  program crash as it should?
</p>
<p>
  The answer is a quizzical "No". <code>doSomething</code> will catch
  the undefined error and "re-throw" it by emitting it as an <code>error</code>
  event. Since you are listening for those error events and ignoring them,
  your program will carry on as if nothing bad happened. But in fact,
  something terrible happened. This is an uncaught exception from the
  runtime's point of view, and here is what the
  <a href="https://nodejs.org/api/process.html#process_event_uncaughtexception">Node
  docs</a> have to say about those:
</p>
<blockquote><p>
  An unhandled exception means your application - and by extension node.js itself -
  is in an undefined state. Blindly resuming means anything could happen. 
</p></blockquote>
<p>
  By catching every random error and emitting it as if it originated from itself, 
  the <code>doSomething</code> function is potentially placing Node itself into
  an undefined state. This is bad.
</p>
<p>
  You might be tempted to say "But why don't you just add an error event listener
  and crash the program yourself?" The answer is because that's a super brittle
  way of handling errors, e.g. doing a regex test on the error message looking for
  "SyntaxError".
</p>
<p>
  The point is that a library should never, ever capture an error that did not originate
  from itself. I actually discovered this by accidentaly spelling a variable wrong
  and being extremely confused when the stack trace implied that it originated
  from Redis, when in fact it was just me being an idiot. I was even more confused
  when my program didn't crash. Redis was not abundantly important to my application,
  so if it was unavailable for whatever reason (e.g. connection issues) I didn't really care
  and wanted things to keep running. So I had an <code>error</code> event listener
  on Redis which logged the error and let the program keep on running. So imagine my surprise
  when a legitimate syntax error didn't crash the program as it should have.
</p>
<p>
  In conclusion, always handle your errors. But don't handle errors that don't
  belong to you.
</p>