Useful async stack traces in Node.js 14

June 4, 2020 By Nicolas Even

Since version 12, Node.js is supposed to print all of the callers in a stack trace, even if some calls are made asynchronously with the await keyword. Such a stack trace should make debugging a breeze, but, unfortunately, I have found this to work very poorly.

Consider the following program:

const throwSomething = async () => {
await wait();
throw new Error();
};

const fn1 = async () => {
return throwSomething();
};

fn1().catch((e) => console.log(e));

In Node.js 10, this stack trace is printed:

Error
    at throwSomething (.../test.js:5:9)

Not very useful. However, in Node.js 14 the stack trace should be much better. However here it is:

Error
    at throwSomething (.../test.js:5:9)
    at runNextTicks (internal/process/task_queues.js:62:5)
    at processImmediate (internal/timers.js:429:9)

Not better. The problem happens because async stack traces only work when using the await keyword or Promise.all(), not when returning a promise directly.

If we replace return throwSomething() with return await throwSomething(), the output shows the full stack trace:

Error
    at throwSomething (.../test.js:5:9)
    at async fn2 (.../test.js:12:10)

Much better.

Full source code