Throwing Exceptions in JavaScript

Errors are thrown by the engine, and exceptions are thrown by the developer. But what exactly does that mean? In JavaScript, all exceptions are simply objects. While the majority of exceptions are implementations of the global Error class, any old object can be thrown. With this in mind, there are two ways to throw an exception: directly via an Error object, and through a custom object.

Generic exceptions

While the built-in Error class is fairly well defined—including such things as the filename, line number, and stack trace to name a few—when it comes down to it, the most important thing to take note of is the message. The first—and often only—parameter to be passed during Error instantiation, the message is a human-readable error that can often be related directly to the end user. Throwing a generic exception is almost as simple as it sounds. All it takes is to instantiate an exception object—with the first parameter of the Error constructor being the error message—and then… "throw" it.

throw new Error('Exception message');

error.code vs. error.message

It is important to note here that, while the error message is the human readable error data, Node.js also provides an error code that identifies the kind of error that is being thrown. This value is useful as it allows you to programmatically adapt to errors that may be thrown, regardless of the message contained within the error.

While error codes are generally used for system errors, when creating custom errors by extending the error class (see Custom exceptions below for more details), a custom code can be defined and used for more structured error definitions.

function CustomException(message) {
  const error = new Error(message);

  error.code = "THIS_IS_A_CUSTOM_ERROR_CODE";
  return error;
}

CustomException.prototype = Object.create(Error.prototype);

Custom exceptions

While it is possible to throw any object, best practice is to extend the Error object with a new class. In environments that support it, this allows for features like the automatic stack trace to be included in the exception response, which can be crucial when it comes to diagnosing issues later down the line.

function CustomException(message) {
  const error = new Error(message);
  return error;
}

CustomException.prototype = Object.create(Error.prototype);

With a custom exception object created, all we have to do is throw it like any other error:

throw new CustomException('Exception message');

Another big advantage to extending the Error object, rather than throwing a generic error, is that additional metadata can be included with the error and retrieved later. This can be incredibly valuable in debugging and error reporting, as sometimes a plain text message simply isn't enough. For example, you can include the values of local variables or state that can help you debug the problem.

function CustomException(message, metadata) {
  const error = new Error(message);
  error.metadata = metadata;
  return error;
}

Outside of the data included in the Error object, when using the Rollbar notifier for JavaScript additional data is included with the report as well. This includes contextual information like the browser and user.

// Caught errors
try {
  doSomething();
} catch (e) {
  Rollbar.error("Something went wrong", e);
}

Writing to the console

In JavaScript, the console is where all logs can be found (more on that in Where are JavaScript Errors Logged?). Thankfully, actually writing data to the console is incredibly straightforward. To accomplish this, simply call the console.log() method, with the message you would like to write to the log.

console.log("Top level");