Custom JavaScript Errors in ES6

A few years ago I gave a talk at MountainWest JS called Error Handling in node.js. In that talk I extolled the virtues of creating custom error objects by extending the built-in Error type. Most of the content was inspired by Guillermo’s seminal A String is Not an Error. Let’s revisit that advice in the world of ES6 classes.

Why Do We Care About Error Objects?

Error objects are the only way to get stack traces in JavaScript. If you callback with or throw or reject a promise with a string instead of an Error, you won’t be able to trace where the error came from.

throw "this is not an error"
test.js:1
(function (exports, require, module, __filename, __dirname) { throw "this is not an error"
^
this is not an error
throw new Error("this is not an error")
test.js:1
(function (exports, require, module, __filename, __dirname) { throw new Error("this is not an error")
^

Error: this is not an error
at Object.<anonymous> (test.js:1:69)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js

Why Bother with Custom Errors?

Given that Error objects are much better than strings, what if we need to include more than a message with our error? For example what if we also want to include an error code?

var error = new Error("Could not access the file")
error.code = "EACCES"
  1. Your error instance can’t have any custom methods

How Do We Make Custom Errors?

Making custom error objects used to be a little bit tricky! Lots of blog posts had to be written about it (mostly because inheritance in JS is a little bit tricky.) Thankfully ES6 has made this a little bit easier.

class MyError extends Error {}
Error: there was a problem
at GoodError (custom-errors.js:1:63)
at getError (custom-errors.js:4:25)
at Object.<anonymous (custom-errors.js:7:1)
Error: there was a problem
at getError (fancy-errors.js:9:5)
at Object.<anonymous> (fancy-errors.js:12:1)

Tl;dr

  1. Always use error objects instead of strings to preserve a stack trace
  2. Appending common properties to errors is used by node.js to provide additional context
  3. Custom error objects allow for adding your own methods and make capturing additional metadata into your errors a lot of easier
  4. class MyError extends Error {} is basically good enough
  5. Override the constructor and use Error.captureStackTrace if you want to streamline the stack trace a bit.

UI Engineering Leader

UI Engineering Leader