Node.js Error Handling

Node.js Error Handling – ERR_ASYNC_CALLBACK

Next up in our deep Node.js Error Handling series we’ll be tackling the ERR_ASYNC_CALLBACK error type, which falls into the broader System Errors category of Node. Node throws a System Error when an exception occurs within the program’s runtime environment, and such errors are typically an indication that there was an operational problem within the application. An ERR_ASYNC_CALLBACK error indicates that an attempt was made to register a non-function data type as an async_hooks constructor callback.

Throughout this article we’ll explore the ERR_ASYNC_CALLBACK system error by looking at where it sits in the greater Node.js Error Class Hierarchy. We’ll also examine the basics of the async_hooks module, and how improper use could result in ERR_ASYNC_CALLBACKs, so let’s dig in!

The Technical Rundown

Most Node.js errors inherit from the Error base class, or extend from an inherited class therein. The full error hierarchy of this error is:

Full Code Sample

Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.

When Should You Use It?

We won’t go too in-depth on it since it’s a big topic, but we should briefly review how Node handles asynchronous hooks via the async_hooks module. The async_hooks module provides a way to register callbacks for tracking the lifetime of asynchronous resources within your application. In this context a resource is any object with an associated callback, such as a net connection, and each resource can (and will often be) called multiple times. A resource can also be closed before the callback is called.

The basic AsyncHook class constructor accepts a handful of parameters, each of which is expected to be the callback function for different stages in the asynchronous execution process. As seen in the source code, each of these arguments, if defined, is expected to be a function so a callback can be performed.

We’ll test async_hooks by defining each of the five basic callback functions:

Now we’ll add each of these functions to the appropriate callbacks object attribute, which is passed to the async_hooks constructor:

After creating a hook with the passed callbacks we enable() it, then create a basic server and listen on port 8080 for incoming connections. We also wait one second to output a basic message to the log. Meanwhile, all the async_hooks callback functions are outputting info when they are invoked.

Executing this test code produces the following output:

This output shows the basic execution pattern of these asynchronous callbacks, including the callback function, the asynchronous id, and (in the case of init), the type. Since our server isn’t explicitly halted in our code it will sit and wait for connections, so we can explicitly connect via curl in a terminal:

And this will immediately trigger additional asynchronous callbacks with new Ids:

We’re missing a good deal of useful information, such as timestamps, so we can execute the testOnAsyncHook.js file, which uses the handy on-async-hook package to output such trace details:

All we’re doing here is creating an onAsyncHook(...) instance and having it log trace data to the console. We then create a basic server that responds to incoming requests with Hello world, before we automatically stop the async hook after two seconds. Executing this test produces the following output:

Tracing modules like this can help you perform very explicit tracking and management of the various resources being used and invoked in your Node application. However, this is just to improve the output we see, but let’s perform one more test where we don’t pass exactly the right argument types to the async_hooks.createHook(...) constructor:

Everything is the same as before, except you may notice that the callbacks.init property is set to false, rather than assigning it to the existing init function. When we execute this code we suddenly get a TypeError with an ERR_ASYNC_CALLBACK code, indicating that the init argument passed to the AsyncHook constructor should be a function:

Airbrake’s robust error monitoring software provides real-time error monitoring and automatic error reporting for all your development projects. Airbrake’s state of the art web dashboard ensures you receive round-the-clock status updates on your application’s health and error rates. No matter what you’re working on, Airbrake easily integrates with all the most popular languages and frameworks. Plus, Airbrake makes it easy to customize error parameters, while giving you complete control of the active error filter system, so you only gather the errors that matter most.

Check out Airbrake’s error monitoring software today and see for yourself why so many of the world’s best engineering teams use Airbrake to revolutionize their exception handling practices!