Better error handling with window.onerror

By karlcow

Introduction

onerror is a DOM event handler. It is started when an error occurs during object loading. While window.onerror is an event handler, there is no error event being fired: instead, when there is an uncaught exception or compile-time error, the window.onerror event handler is called with contextual information about the error, making for some more powerful error handling opportunities.

uncaught exceptions
throw "some messages"
call_something_undefined();
cross_origin_iframe.contentWindow.document;, a security exception
compile error
<script>{</script>
<script>for(;)</script>
<script>"oops</script>
setTimeout("{", 10);, it will attempt to compile the first argument as a script

Scripts are first compiled and then they are run. If the compile is successful the first time, it is not compiled again later on. However, a script or a function that compiled successfully might have runtime errors when it is run, and a function can be called multiple times.

In this article we will look at when and how to use window.onerror, along with some examples to get you started.

When should we use window.onerror?

Usually when there is an error in our JavaScript code we open the browser error console to check what errors are being thrown. This can become cumbersome when developing complex web applications using a lot of JavaScript code. How nice would it be to be able to deal with these errors in a programmatic way through JavaScript?

window.onerror allows us to do just this, allowing us to report error messages in a more convenient fashion that suits our context. We will cover a few ways to use window.onerror next.

A very simple message

To understand what is happening, let’s create a JavaScript debug.js with this simple script.

window.onerror = function(message, url, linenumber) {
  alert("JavaScript error: " + message + " on line " + linenumber + " for " + url);
}

The arguments accepted by our function are:

  • message: the error message (DOMString)
  • url: the URL of the file containing the error (DOMString)
  • linenumber: the line number where the error occurred (unsigned long)

If the return value is true, then the error is handled, else it is not handled.

Now let's create a second script — clumsy.js:

document.alert("Ooops, I'm bad with paranthesis!"

Finally we'll create an HTML page that calls these two scripts:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Demo of window.onerror</title>
    <script src="debug.js"></script>
    <script src="clumsy.js"></script>
</head>
<body>
    <p>This should throw an alert message.</p>
</body>
</html>

When accessed by a browser that supports window.onerror, a pop-up will appear displaying the type of error, the line number where the error occurs and in which file — see Figure 1. This is very useful for debugging.

Error message in Opera

Figure 1: Our simple error massage shown in Opera.

onerror has been attached to window for historical reasons. It could be defined anywhere and would still be working the same way. Script errors might occur in places that have no relation to the document tree at all, such as setTimeout("oops()", 10).

Try the simple error example.

You could also have used a very simple onerror on the document <body>:

<body onerror="alert([event, source, lineno].join('\n'))">

body onerror sets window.onerror just like body onload sets window.onload. Some event handlers on body are reflected on window. So by using body onerror, window.onerror gets a value assigned. When trying to set both in the same context, the last one wins (just like when we assign a value to window.onerror twice).

semantics: The window.onerror reports the error at the script source URL, with the problematic line number, in the script's origin, using the onerror event handler of the script's global object. If the error is still not handled after this, then the error may be reported to the user.

Fancy error messages

If you prefer having a fancier style for the error message than the usual common chrome of the browser.

var fancyerror = function(message, url, linenumber) {
  var errorbox = document.createElement("div");
  errorbox.className = 'fancyerror';
  errorbox.innerHTML = 'JS: <span class="errmsg"' + message.replace('<', '&lt;').replace('>', '&gt;') + '</span><br>line number: ' + linenumber + '<br>located: ' + url;
  document.body.appendChild(errorbox);
  return false;
}

window.onerror = function(message, url, linenumber) {
  return fancyerror(message, url, linenumber);
}

Try the fancy error example. You should try playing with the styling on the fancyerror and errmsg classes to see what you can come up with.

Suppressing errors: a dangerous feature?

When focusing on other things during development work, you might want to suppress all JavaScript error messages to start off with, until you are ready to do a proper round of debugging. This can be done like so:

function noErrorMa() {
  return true;
}

window.onerror = noErrorMa;

A better error handling with server logging

A pop-up window is not very useful, specifically if there is a lot of opportunities for errors. It would also be neat to be able to collect all these errors in a single file so we can inspect them later on. XMLHttpRequest offers an elegant way to record messages on a server. On the client side, the JavaScript will look something like this:

window.onerror = function(message, url, linenumber) {
  if (window.XMLHttpRequest) {

    var xhr = new XMLHttpRequest();
    var scripturl = "http://yourdomain.example.com/log";
    var log = linenumber + message + url;
    xhr.open("POST", scripturl);
    xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
    xhr.send(log);
  }
  return true;
}

Then as usual when dealing with XMLHttpRequest, you just need to create a script which will parse the XMLHttpRequest data and save it locally.

Security

To prevent information leaking from one server to the other, it is important to be careful with scripts that have two different origins. If the script URL is has a different origin to the document then the three arguments returned by window.onerror are always ‘Script error.’, ‘’, 0. Read X-Script-Origin, we hardly knew ye for more details.

Browsers supporting window.onerror

  • Chrome 13+
  • Firefox 6.0+
  • Internet Explorer 5.5+
  • Opera 11.60+
  • Safari 5.1+
code,

Karl is working from Montréal, Canada. It has been participating to the Web since its inception under different roles including Web designer, CTO, W3C staff, translations volunteer, bits pusher, http poet, …


This article is licensed under a Creative Commons Attribution 3.0 Unported license.

Comments

  • photo

    Thiemo

    Wednesday, December 14, 2011

    This is funny. Do you see the "/code /code" at the end of the article? This is a bug in Opera 11.60 (Build 1185) with textareas. Same thing happened to me in my own web application. I was looking for an error in my regular expressions but it's the browser. Just to let you know.
  • photo

    Maxim

    Wednesday, December 14, 2011

    Some other browsers require "return false" to let browser handle same error. Do your solution is right?
  • photo

    Swapnil Rustagi

    Thursday, December 15, 2011

    Excuse me but there is no version as Firefox 6.1. Might be Firefox 6.0, because 6.0.1 was just a small security/maintenance update.
    Kudos to Microsoft. Internet Explorer, surprisingly was the only browser to support window.onerror prior to 2011 if this article is correct.
  • photo

    Swapnil Rustagi

    Friday, December 16, 2011

    Originally posted by chrismills:

    Are you sure? If you Google Firefox 6.1, you see such a version talked about in a lot of posts.



    Oh yes, I am 100% sure. There is no Firefox 6.1 at http://www.mozilla.org/en-US/firefox/releases/

    Also the page http://www.mozilla.org/en-US/firefox/6.1/releasenotes/ does not exist indicating that there was never a Firefox 6.1. The only releases were 6.0.1 and 6.0.2 both of which were maintenance/security updates.

    Don't blindly trust search results. If you search Windows 10, you will even find several results for that too.
  • photo

    Chris Mills

    Friday, December 16, 2011

    @Swapnil Rustagi

    ok, I'll update it ;-)
  • photo

    timwright12

    Monday, December 19, 2011

    Any word on this outputting multiple errors? Unless I'm mistaken, it looks like it's stopping at the 1st. Maybe the console does that too... I guess I'd have to check.
  • photo

    Vahagn Grigoryan

    Wednesday, December 28, 2011

    thanks for the article
  • photo

    Isuru Nanayakkara

    Friday, January 6, 2012

    great article! I was looking for something like this. Thanks.
  • photo

    Lollo Andersen

    Tuesday, May 29, 2012

    thanks!
No new comments accepted.