JavaScript stack overflow error

From time to time, I’ve blogged about JavaScript browser limits and how they present themselves. I started out by discussing the long-running script dialog and then moved on to other performance issues. I thought I had covered most of the annoying and ill-explained JavaScript limits, but this past week I ran across another that is worth discussing: stack overflow errors.

I’ve written about how too much recursion can lead to performance issues. Most browsers have limits on how much recursion is allowed before the script is automatically canceled. This is a limit that is separate from the one determining if the script is long-running. And the limit is really less about recursive calls so much as it is about the size of the JavaScript call stack.

Not surprisingly, different browsers have different call stack sizes. Also not surprisingly, the method that they use to determine the call stack varies as well. The various call stack sizes I could measure are (give or take, might be off by 1 or 2):

  • Internet Explorer 7: 1,789
  • Firefox 3: 3,000
  • Chrome 1: 21,837
  • Opera 9.62: 10,000
  • Safari 3.2: 500

Some have said, but I cannot confirm, that IE and Opera’s call stack size are somewhat tied to the amount of RAM on the system. All other browsers have this set by a default. It’s also worth noting that WebKit seems to have a much higher limit and that Safari imposes a stricter limit on the JavaScript engine.

There are two common scenarios in which this limit could be reached. The first is simple recursion, such as:

function recurse(){
    recurse();
}

recurse();

The second is a more devious and harder-to-identify issue, especially in large code bases, where two functions each call the other, such as:

function doSomething(){
    doSomethingElse();
}

function doSomethingElse(){
    doSomething();
}

doSomething();

In each case, the browser will end up stopping your code and (hopefully) display a message about the issue:

  • Internet Explorer 7: “Stack overflow at line x”
  • Firefox 3:”Too much recursion”
  • Chrome 1: n/a
  • Opera 9.62: “Abort (control stack overflow)”
  • Safari 3.2:”RangeError: Maximum call stack size exceeded.”

Chrome is the only browser that doesn’t display a message indicating the problem. If you see any of these error messages pop up, it means one of the two patterns are involved and need to be changed. There’s usually a line number and file name associated with this error, so it’s fairly straightforward to debug.

Perhaps the most interesting part of stack overflow errors is that they are actual JavaScript errors in some browsers, and can therefore be trapped using a try-catch statement. The exception type varies based on the browser being used. In Firefox, it’s an InternalError, in Safari and Chrome, it’s a RangeError, and Internet Explorer throws a generic Error type (Opera doesn’t throw an error, it just stops the JavaScript engine) . So, it’s possible to do something like this:

try {
    recurse();
} catch (ex){
    alert("Too much recursion!");
}

If left untrapped, these errors bubble up as any other error would (in Firefox, it ends up in the Firebug console, Safari/Chrome it shows up in the console) except in Internet Explorer. IE will not only display a JavaScript error but will also display an ugly dialog box that looks just like an alert with the stack overflow message.

Now, just because it’s possible to trap this error in almost all browsers doesn’t mean that you should. No code should end up in production with even the possibility of a stack overflow error present. Such instances indicate poor code design and should be re-evaluated and/or re-designed to avoid this error. Consider this post as an aid in debugging this issue, not as a license to trap and disguise it.

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.