catchjs

What causes TypeError on live web sites?

TypeErrors are the second most common error type on the web. They are the JavaScript engine's way of telling the programmer that they're operating on something that has the wrong type. We could be using a number as a function, or using an object as a constructor, or something similar. It turns out that when TypeErrors happen on a live website, almost all of them happen for the same reason - the variable being operated upon has no value: It is null or undefined.

If the variable is declared but has the wrong type, it will produce a TypeError. If it is not declared, it will produce a ReferenceError.

This post builds on our JavaScript Errors and Performance in the Wild 2020 study, where we crawled the top 1 million domains in order to learn about errors and performance on the web.
We do JavaScript error tracking for our customers. This time we decided to track errors on the entire web. In our crawl, TypeErrors made up 30% of all errors found, and occurred on 4.7% of all sites.

Null and undefined cause 97% of TypeErrors

When TypeErrors happen during development, it is often immediately obvious what went wrong. However, when they happen on live websites, they seem to often be a symptom of interdependencies between different parts of the system, where a change in one place cause breakage in another. In our crawl, we found that on live websites, a whole 97% of TypeErrors happen because code wants to operate on a value that is missing. In most cases the code either wants to operate on an element in the document that isn't there, or it wants to use a piece of code that hasn't been loaded. Very often it is because the document has changed, in a way that was unexpected by the code, or because a JavaScript library hasn't loaded.

A common manifestation of the TypeError will have message of the form "Cannot read property 'property_name' of undefined/null". The last word in that message, undefined or null, tells you something about how the error happened:

Below we'll dig into two common scenarios, that illustrate how TypeErrors tend to happen in the wild.

$ is not a function

This exact message, "$ is not a function", happened on 0.2% of websites, made up 4.5% of all TypeErrors and happened on 1.2% of all sites with errors.

The error indicates that the $ variable is declared, but it is not a function. How does this happen? When loaded, jQuery assigns itself to two global variables $ and jQuery, which can both be called as a function. However, claiming ownership of the name $ can be considered risky, as it may conflict with any other library using this name. Thus, jQuery provides the method $.noConflict() which will set the dollar-sign variable back to whatever it was before jQuery was loaded, or set it to undefined if jQuery was the first to touch it. Throwing in the $.noConflict() line without careful consideration can then ironically lead to conflicts, if later code expects to find jQuery assigned to $.

For example:

<script src="jquery.js"></script>
<script>
    $.noConflict();
    $(document).ready(initSite);
</script>

The second use of $ will fail, because the noConflict() call has un-defined the name right underneath our noses. It turns out this situation is extremely common.

This example is specific to jQuery, but it illustrates a common problem: There is an untrue assumption made about the runtime environment, and code will break when it becomes clear that assumption is false. Libraries and plugins that are intended to run in heterogenous environments have no guarantees that its dependencies are met, so they need to check that they are available at runtime, or make dependency problems less likely, for example through the use of package managers.

Cannot read property 'addEventListener' of null

Errors of the form "Cannot read property [property_name] of null" occurred on a full 1% of all websites, made up 22% of all TypeErrors and happened on 9% of all sites with errors.

The most common TypeError are variations of these, where something is done with a value that is null. Most commonly, this comes from missing elements in the document. For example, a programmer could do this:

var el = document.getElementById("my-elem");
el.addEventListener("click", handleClick); 

If no element in the document has the id "my-elem", the variable el will have value null, leading to a crash when we try to call addEventListener.

The top 20 TypeErrors on the web

The twenty most common variants of TypeError messages found in our crawl are the following. Notice a pattern?

TypeError messageDistinct sites with this error
Cannot read property 'envelope' of undefined2123
$ is not a function2108
Cannot read property 'addEventListener' of null1651
Cannot read property 'appendChild' of null1378
Cannot read property 'msie' of undefined1287
Cannot read property 'style' of null1285
Cannot read property 'setRushSimulatedLocalEvents' of undefined1109
Cannot read property 'top' of undefined1063
Cannot set property 'innerHTML' of null1007
Cannot read property 'length' of undefined772
Cannot set property 'onclick' of null640
Cannot read property 'split' of undefined548
Cannot read property 'replace' of undefined498
e.indexOf is not a function494
Cannot read property '0' of undefined486
Cannot read property 'fn' of undefined476
$(...).live is not a function460
Cannot read property 'style' of undefined436
Cannot read property 'querySelector' of null428
Cannot read property 'add' of null381

Everything comes from unexpected nulls and undefineds. Note in particular number 1 and 7, between them causing errors on 0.3% of all the crawled websites. These are both related to third-party advertising scripts, whose code content the site owner likely has little control over.

Two other common errors on the web are ReferenceError and SyntaxError. Click the links to learn about the characteristics of these errors found in our crawl.