Overview

All major browsers (if beta versions are included) now support accessing stack traces from scripts. However, no single browser agree on the details of how stack traces are accessible.

Examples

function f() {
  try {
    doSomething();
  } catch (err) {
    alert(err.stack)
  }
}
 
f();

Should alert something like:

ReferenceError: doSomething is not defined
    at f (http://www.example.com/temp.html:5:5)
    at http://www.example.com/temp.html:11:1

Background

Firefox was the first browser to expose a stack property on the Error object. A new-line separated string was used for this purpose. Each line of the string contained the function name (if any) followed by @, URL and line number.

The next browser to add support for stack was Chrome. It changed the format slightly to include the column number and it also limited the number of stack traces to 10 by default but allows the script to change this by setting Error.stackTraceLimit.

Both Safari and IE have added support for stack in their current beta versions.

Internet Explorer Chrome Firefox Safari Opera
The property is added when an Error object is created X X X
The property is added when the object/error is thrown X* X
get X X
set X X
value X X X
writable X X
configurable X X
enumerable X X X X
Includes column numbers X X
stackTraceLimit X X

* IE only adds the stack property to objects that have Error.prototype on the prototype chain

All browsers add the stack property as an instance property.

Formatting of stack

All browsers return stack as a “\n” separated string.

IE & Chrome

ReferenceError: d is not defined
    at runScript (http://ie.microsoft.com/testdrive/browser/ExploreErrorStack/:356:30)

Firefox & Safari

runScript@http://ie.microsoft.com/testdrive/browser/ExploreErrorStack/:356

Opera

runScript([arguments not available])@http://ie.microsoft.com/testdrive/browser/ExploreErrorStack/:356

Property

The stack property should be a [[Configurable]], [[Writable]], [[Enumerable]] data property. The reason to make this writable is because old code out there add stack manually by walking the caller chain and they might depend on their own custom value of the stack property.

The property should be added as an instance property when an object that inherits from Error is created. (See discussion)

Suggested formatting

Stack ::= ErrorName ": " ErrorMessage ("\n    at " StackFrame)+

StackFrame ::= (FunctionName " ")? "(" StackLocation ")"
             | StackLocation

StackLocation ::= "eval at " FunctionName " (" StackURLLocation ")"
                | StackURLLocation

StackURLLocation ::= URL ":" RowNumber ":" ColumnNumber

for example:

ReferenceError: doSomething is not defined
    at f (http://www.example.com/temp.html:5:5)
    at g (eval at h (http://www.example.com/temp.html:6:5))
    at http://www.example.com/temp.html:11:1

This is intended to match Internet Explorer and Chrome. It has some benefits over what the other browsers provide.

  • Provides the column number. Requiring both row and column is essential because it is very common for large scale applications to minimize the source code and end up with multiple statements per line.
  • Points out that the code was eval’ed.

The FunctionName part is intentionally left underspecified to allow implementations to provide information like “new”, arguments, method name etc.

For more details about the formatting of error stack in V8 please refer to: http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

Providing ErrorName and ErrorMessage is a bit dubious since this information is already available on Error instance objects but it is convenient for tools that upload the stack trace to a server.

The " at " part adds no real value except that it makes the string a bit more readable.

Error.stackTraceLimit

In some script engines it is costly to keep the entire stack trace in memory and therefore an engine may limit the size of the stack trace. This is controlled by a [[Configurable]], [[Writable]], [[Enumerable]] data property called stackTraceLimit on the Error object. (The default in IE and Chrome is 10 but we could make this implementation specific.) Setting this to 0 prevents any stack trace from being collected and setting this to Infinity should keep as much of the stack trace as possible.

Discussion

Having the stack be a string that has to be manually parsed is really silly. However, Safari tried to return an array of stuff and it turned out that it broke things. We could provide an alternative API to extract relevant details but at this point we should strive to make implementations compatible.

Some browsers add the stack property only when an error is thrown. This might be a better solution but there is code out there that expects there to be a stack property on newly created Error objects. https://code.google.com/searchframe#epIciakqvFc/trunk/closure/goog/debug/error.js&l=40

The formatting of the string is a bit arbitrary. The goal here is to spec something and the V8 style formatting provides more details than the SpiderMonkey style formatting.


I generally like this idea. I don’t know what kind of compat problems we’d have in FF if we changed our format, but I can analyze our addons to find out how many do stack trace parsing, to get a feel for what kind of breakage might occur. It’s harder for me to know what kinds of problems this might cause for web content. But we could start by looking at cross-engine compatibility libraries for stack traces like http://stacktracejs.com/.

We should be careful not to over-specify: we want to leave engines with the freedom to do optimizations like inlining. But we can strive for better compatibility in stack trace formats between engines.

Dave Herman 2012/06/07 20:14

Mark Miller objects to any capability leak, which seems likely if we reflect e.stackFrames. Mark also is concerned about information leaks via a string.

When I implement SpiderMonkey’s e.stack back in the day (first!), I did not want to leak information such as argument values. I also wanted to make it easy to split the string and do whatever formatting seemed best, but I agree V8’s format is not much harder to “parse” via split, and it is more readable.

Brendan Eich 2012/08/02 21:53

Another thought: for compat, you said that err.stack has to be a string. But maybe we could add another structured stack trace for easier programmatic access as well, e.g. err.stackFrames or err.stackEntries or something like that?

Dave Herman 2012/06/07 20:20

 
strawman/error_stack.txt · Last modified: 2012/08/02 21:55 by brendan
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki