/flags/javascript/node-stack-trace-limit
node --stack-trace-limit: show more than 10 frames in a JavaScript stack trace
- tool
- JavaScript
- command
- node
- flag
- --stack-trace-limit=<limit>
- default
- 10
node --stack-trace-limit=N app.js sets how many stack frames V8 records in error.stack. The default is 10, which is why long Node.js traces stop after ten at ... lines and hide the frame you were looking for. 0 disables stack collection; any number raises the limit. The same value is available in code as Error.stackTraceLimit.
Default, larger and zero
cat > deep.js <<'EOF'
function level(n) { if (n === 0) throw new Error("boom"); level(n - 1); }
try { level(15); } catch (e) {
const frames = e.stack.split("\n").filter((l) => l.trimStart().startsWith("at "));
console.log("Error.stackTraceLimit =", Error.stackTraceLimit, "-> frames:", frames.length);
}
EOF
node deep.js
node --stack-trace-limit=50 deep.js
node --stack-trace-limit=0 deep.js
NODE_OPTIONS=--stack-trace-limit=25 node deep.js
node -e 'Error.stackTraceLimit = Infinity; function f(n) { if (!n) throw new Error("x"); f(n - 1); } try { f(30); } catch (e) { console.log(e.stack.split("\n").length - 1, "frames with Infinity"); }'Output
Error.stackTraceLimit = 10 -> frames: 10 Error.stackTraceLimit = 50 -> frames: 24 Error.stackTraceLimit = 0 -> frames: 0 Error.stackTraceLimit = 25 -> frames: 24 39 frames with Infinity
With the default only 10 frames survive, although the stack is 24 frames deep: 16 calls of level plus the frames of the script itself and of the Node.js module loader. With 50 (or 25 through NODE_OPTIONS) all 24 are kept. With 0 the stack string holds only the message line.
Ways to set the limit
| Method | Scope | Notes |
|---|---|---|
| node --stack-trace-limit=50 app.js | Whole process | Documented in the Node.js CLI reference |
| NODE_OPTIONS=--stack-trace-limit=50 | Process and child node processes | Useful with npm scripts, test runners, CLIs |
| Error.stackTraceLimit = 50 | Errors created after the assignment | Works in code, also in V8-based browsers |
| Error.stackTraceLimit = Infinity | Errors created after the assignment | Keeps every frame |
| Error.captureStackTrace(obj, fn) | One object | Records a stack on obj, hiding frames above fn |
The limit applies when the error object is created, not when stack is read. Raising Error.stackTraceLimit inside a catch block does not bring back frames of an error that already exists.
When it helps
- Errors inside libraries: a TypeError: Cannot read properties of undefined raised deep inside a framework often shows ten framework frames and none of your code. A limit of 30-50 reaches your call site.
- Async code:
awaitchains are reconstructed by V8 as async frames; they also count against the limit. - Recursion: for Maximum call stack size exceeded the default 10 frames are usually identical lines, which already tells you which function recurses. Raising the limit to
Infinitythere prints thousands of lines and is rarely useful. To change how deep the stack can go, see node --stack-size, a different option.
Pitfalls
- A high limit costs CPU each time an
Erroris constructed, which matters for code that uses exceptions for control flow. - Any code that assigns
Error.stackTraceLimitat start-up, including a dependency, overrides the command-line value; print the property at run time if the option seems ignored. Error.stackTraceLimitandError.captureStackTraceare V8 APIs. Code that must run in every JavaScript engine should not depend on them.
FAQ
Why is my Node.js stack trace cut off after 10 lines?
V8 collects only 10 frames by default. Start Node.js with --stack-trace-limit=50, set Error.stackTraceLimit = 50 early in the program, or use Infinity to keep every frame.
Does --stack-trace-limit affect performance?
Collecting frames costs time each time an Error is created, so very large limits slow down code that creates many errors. Use a high value while debugging and keep the default in hot production paths.
Can I set it in NODE_OPTIONS?
Yes. NODE_OPTIONS=--stack-trace-limit=50 node app.js works and also applies to child Node.js processes, which is handy for test runners and CLIs that spawn other node processes.