Rethrowing Errors In JavaScript And Node.js

When dealing with errors, handling them at the perimeter of your application isn't always sufficient. By the time the error bubbles up, you've often lost a lot of the context in which the error was thrown. As such, people will sometimes catch an error, record it locally in some way, and then rethrow it. In ColdFusion, we use the rethrow() function. But, in JavaScript and Node.js, there is no rethrow() function; instead, you just throw() the original error object.

This works in both JavaScript (in general) and in Node.js. But, for the context of the demo, I'll be running my code in Node.js where I can require my custom error object. In the following code, I'll be throwing an error in one method, catching it and rethrowing it in another method, and then finally catching it in yet another method:

// Require our core application modules.

var appError = require( "./app-error" ).createAppError;

// Start a method chain that will throw an error:

// --> foo() [catches error]

// -----> bar() [catches / rethrows error]

// --------> baz() [throws error]

foo();

function foo() {

try {

bar();

} catch ( error ) {

console.log( "Error caught in Foo():", error.message );

console.log( error.stack );

}

}

function bar() {

// In this case, we are going to catch any errors thrown by baz(), log them to the

// console, and then rethrow them.

try {

baz();

} catch ( error ) {

console.log( "Error caught and rethrown in Bar():", error.message );

// In JavaScript, there is no special "rethrow" keyword. You simply throw() the

// error that you caught. This will maintain the original stacktrace recorded by

// the error as you "pass it back up" the call-stack.

throw( error );

}

}

function baz() {

throw(

appError({

type: "App.CustomError",

message: "Something went wrong in baz().",

detail: "Testing errors and rethrowing in JavaScript and Node.js."

})

);

}

As you can see, the error, thrown in baz() was rethrown in bar(). And, yet, when the error is finally caught in foo(), we get the following terminal output:

As you can see from the stacktrace, the error caught in foo() was the same error thrown in baz() and then rethrown in bar().

Rethrowing errors is a great way to inspect [and log] an error locally but defer the handling of it to a point higher up in the call-stack. Of course, having a rich, robust error object is also great for this. I'm just happy that this approach works in JavaScript and Node.js as well as other programming languages, like ColdFusion.

I am the co-founder and lead engineer at InVision App, Inc — the world's leading prototyping,
collaboration & workflow platform. I also rock out in JavaScript and ColdFusion 24x7 and I dream about
promise resolving asynchronously.