How can I get a JavaScript stack trace when I throw an exception?
Edit 2 (2017):
In all modern browsers you can simply call: console.trace();
(MDN Reference)
Edit 1 (2013):
A better (and simpler) solution as pointed out in the comments on the original question is to use the stack
property of an Error
object like so:
function stackTrace() {
var err = new Error();
return err.stack;
}
This will generate output like this:
DBX.Utils.stackTrace@http://localhost:49573/assets/js/scripts.js:44
DBX.Console.Debug@http://localhost:49573/assets/js/scripts.js:9
.success@http://localhost:49573/:462
x.Callbacks/c@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4
x.Callbacks/p.fireWith@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4
k@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6
.send/r@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6
Giving the name of the calling function along with the URL, its calling function, and so on.
Original (2009):
A modified version of this snippet may somewhat help:
function stacktrace() {
function st2(f) {
return !f ? [] :
st2(f.caller).concat([f.toString().split('(')[0].substring(9) + '(' + f.arguments.join(',') + ')']);
}
return st2(arguments.callee.caller);
}
Print current stack trace in JavaScript
This line of code gets a stack trace and prints it:
console.trace();
Source: https://developer.mozilla.org/en-US/docs/Web/API/Console/trace
How can I get a JS stack trace without halting the script?
Throwing an error will halt the stack unless caught by a try/catch.
function getStack() {
try {
throw new Error();
} catch(e) {
return e.stack;
}
}
Invoking getStack from within any function will print out the stack from there.
Note, the method names in the stack are not affected by sourcemaps, so if you're dealing with minified code you might still get obfuscated names.
Why am I not seeing a stack trace with 'throw new Error'?
You don't see the whole stack trace because you throw an error in A() asynchronously (using setTimeout). If you throw it synchronously - you'll see the trace c()->b()->a().
Try it: http://jsbin.com/yirorimewe/1/edit?js,console
How to print stacktrace once an exception is thrown before the catch block (stack unwinding)
I'm posting this in case anyone came across the same question and wanted a quick useful answer.
I've ended up overriding the main C++ throw exception behavior using this gist
I've changed a few things in the __cxa_throw
function to tackle my own issue and used boost::stacktrace
to get a more human-readable stack trace.
Re-throwing exception in NodeJS and not losing stack trace
I'm not aware of a native method like Java's and I've not found an elegant solution for wrapping errors yet.
The problem with creating a new Error
is you can lose metadata that was attached to the original Error
that was thrown, the stack trace and type are generally the important items lost.
Making modifications to an existing thrown error is quicker, but it is still possible to modify data from the error out of existence. It also feels wrong to be poking around in an error that was created somewhere else.
Create a new Error and new stack
The .stack
property of a new Error
is a plain string and can be modified to say what you like before it is thrown. Replacing an errors stack
property completely can get really confusing for debugging though.
When the original thrown error and the error handler are in separate locations or files (which is common with promises), you might be able to trace the source of the original error but not trace the handler where the error was actually trapped. To avoid this it's good to keep some references to both the original and new error in the stack
. It's also useful to have access to the complete original error if there was additional metadata stored in it.
Here's an example of catching an error, wrapping it in a new error but adding the original stack
and storing the error
:
try {
throw new Error('First one')
} catch (error) {
let e = new Error(`Rethrowing the "${error.message}" error`)
e.original_error = error
e.stack = e.stack.split('\n').slice(0,2).join('\n') + '\n' +
error.stack
throw e
}
Which throws:
/so/42754270/test.js:9
throw e
^
Error: Rethrowing the "First one" error
at test (/so/42754270/test.js:5:13)
Error: First one
at test (/so/42754270/test.js:3:11)
at Object.<anonymous> (/so/42754270/test.js:13:1)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
So we've created a new generic Error
. Unfortunately the type of the original error becomes hidden from the output but the error
has been attached as .original_error
so it can still be accessed. The new stack
has been largely removed except for the generating line which is important, and the original errors stack
appended.
Any tools that try to parse stack traces might not work with this change or best case, they detect two errors.
Rethrowing with ES2015+ Error Classes
Making this into a reusable ES2015+ Error class:
class RethrownError extends Error {
constructor(message, error){
super(message)
this.name = this.constructor.name
if (!error) throw new Error('RethrownError requires a message and error')
this.original_error = error
this.stack_before_rethrow = this.stack
const message_lines = (this.message.match(/\n/g)||[]).length + 1
this.stack = this.stack.split('\n').slice(0, message_lines+1).join('\n') + '\n' +
error.stack
}
}
throw new RethrownError(`Oh no a "${error.message}" error`, error)
Results in
/so/42754270/test2.js:31
throw new RethrownError(`Oh no a "${error.message}"" error`, error)
^
RethrownError: Oh no a "First one" error
at test (/so/42754270/test2.js:31:11)
Error: First one
at test (/so/42754270/test2.js:29:11)
at Object.<anonymous> (/so/42754270/test2.js:35:1)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
Then you know that whenever you see a RethrownError
that the original error will still be available at .original_error
.
This method is not perfect but it means I can re-type known errors from underlying modules into generic types that be handled more easily, usually with bluebirds filtered catch .catch(TypeError, handler)
Note stack
becomes enumerable here
Same Error with a modified stack
Some times you will need to keep the original error mostly as is.
In this case you can just append/insert the new info onto existing stack.
file = '/home/jim/plumbers'
try {
JSON.parse('k')
} catch (e) {
let message = `JSON parse error in ${file}`
let stack = new Error(message).stack
e.stack = e.stack + '\nFrom previous ' + stack.split('\n').slice(0,2).join('\n') + '\n'
throw e
}
Which returns
/so/42754270/throw_error_replace_stack.js:13
throw e
^
SyntaxError: Unexpected token k in JSON at position 0
at Object.parse (native)
at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:8:13)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
From previous Error: JSON parse error in "/home/jim/plumbers"
at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:11:20)
Also note that the stack processing is simple and assumes the error message is a single line. If you run into multi line error messages you might need to look for \n at
to terminate the message.
How do you get the JavaScript stack trace from Nashorn?
The NashornException
is available as cause of the ScriptException
:
import jdk.nashorn.api.scripting.NashornException;
...
catch (ScriptException e) {
if (e.getCause() instance of NashornException)
String jsStackTrace = NashornException.getScriptStackString(e.getCause());
}
Related Topics
How to Round Up a Number in JavaScript
Replace Multiple Strings at Once
Babel-Loader Jsx Syntaxerror: Unexpected Token
Async Function Not Returning Value, But Console.Log() Does: How to Do
HTML Button to Not Submit Form
How to Use Jquery with Reactjs
How to Split a Long Array into Smaller Arrays, with JavaScript
How to Access the Request Body When Posting Using Node.Js and Express
Cross-Browser Method to Determine Vertical Scroll Percentage in JavaScript
Download JSON Object as a File from Browser
How to Reload Page Every 5 Seconds
How to Get the Browser to Navigate to Url in JavaScript
How to Find If an Array Contains a Specific String in JavaScript/Jquery
Responsive Horizontal Page Sliding