I have a problem that is similar to this one and described in this issue. There are no stack traces in errors that come from fs/promises
when used with async..await, and no way to determine where the error happened.
Given the app:
foo.js
const { bar } = require('./bar');
async function foo() {
await bar();
}
(async () => {
await foo();
})().catch(console.error);
bar.js
const fs = require('fs/promises');
exports.bar = async function bar() {
await fs.readFile('some');
}
When it runs like node foo.js
, this results in an error with no stack trace:
[Error: ENOENT: no such file or directory, open '...\some'] {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: '...\\some'
}
Where error.stack
contains 'ENOENT: no such file or directory, open '...\some'.
When it runs like node --stack_trace_limit=100 -r trace foo.js
with trace
package, like it's suggested in linked sources, this results in this stack trace:
Notice that internal entries are grayed and can be filtered out.
This node --stack_trace_limit=100 -r trace -r clarify foo.js
with trace
and clarify
packages results in this output:
Error: ENOENT: no such file or directory, open '...\some'
at ...\foo.js:8:2
at Object.<anonymous> (...\foo.js:10:3) {
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: '...\\some',
[Symbol(originalCallSite)]: [],
[Symbol(mutatedCallSite)]: [ CallSite {}, CallSite {} ]
}
The problem is that bar.js isn't mentioned in all of the outputs.
My intention is to provide clean error output with no internal entries and the exact location where the error occurs, i.e. line number in bar.js.
What are possible solutions to this problem?
One possible solution is to use Node.js >= v21.2.0. Node.js release v21.2.0 included a commit from PR 49849 that adds stack traces to node:fs/promises
.
package.json
"type": "module"
bar.js
import { readFile } from 'node:fs/promises'
export async function bar() {
await readFile('some')
}
foo.js
import { bar } from './bar.js'
await bar()
Now run node foo.js
to generate the stack trace:
node:internal/fs/promises:638
return new FileHandle(await PromisePrototypeThen(
^
Error: ENOENT: no such file or directory, open 'some'
at async open (node:internal/fs/promises:638:25)
at async readFile (node:internal/fs/promises:1251:14)
at async bar (file:///Users/user/async-stack-trace/bar.js:4:5)
at async file:///Users/user/async-stack-trace/foo.js:4:1 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: 'some'
}
Node.js v22.1.0
foo.js
import { bar } from './bar.js'
async function main() {
await bar()
}
main()
Which after running node foo.js
results in a similar stack trace:
node:internal/fs/promises:638
return new FileHandle(await PromisePrototypeThen(
^
Error: ENOENT: no such file or directory, open 'some'
at async open (node:internal/fs/promises:638:25)
at async readFile (node:internal/fs/promises:1251:14)
at async bar (file:///Users/user/async-stack-trace/bar.js:4:5)
at async main (file:///Users/user/async-stack-trace/foo.js:4:3) {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: 'some'
}
Node.js v22.1.0
package.json
"type": "commonjs"
bar.js
const { readFile } = require('node:fs/promises')
exports.bar = async function bar() {
await readFile('some')
}
foo.js
const { bar } = require('./bar.js')
async function main() {
await bar()
}
main()
After running node foo.js
:
node:internal/fs/promises:638
return new FileHandle(await PromisePrototypeThen(
^
Error: ENOENT: no such file or directory, open 'some'
at async open (node:internal/fs/promises:638:25)
at async readFile (node:internal/fs/promises:1251:14)
at async bar (/Users/user/async-stack-trace/src/bar.js:4:3)
at async main (/Users/user/async-stack-trace/src/foo.js:4:3) {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: 'some'
}
Node.js v22.1.0