Jun 9, 2017 9:00:44 AM | JavaScript Error Handling - X Is Read-Only TypeError

A deep dive into the X Is Read-Only TypeError in JavaScript, including a handful of functional code examples and a brief look at strict mode.

Moving along through our JavaScript Error Handling series today we'll explore the X Is Read-Only TypeError in more detail. An X Is Read-Only TypeError is limited to strict mode and occurs when attempting to alter a read-only property.

In today's article we'll explore the X Is Read-Only TypeError in greater detail, looking at where it resides in the JavaScript Exception hierarchy and examining a few simple code snippets that should help to illustrate how X Is Read-Only TypeErrors are thrown in the first place, so let's get to it!

The Technical Rundown

  • All JavaScript error objects are descendants of the Error object, or an inherited object therein.
  • The TypeError object is inherited from the Error object.
  • The X Is Read-Only TypeError is a descendant of TypeError object.

When Should You Use It?

As mentioned in the introduction, X Is Read-Only TypeErrors can only be thrown while in strict mode. Strict mode is an optional variant of JavaScript that can be opted into by the executing script that will use slightly different (and typically more restrictive) semantics when compared to normal JavaScript. For our purposes one of the biggest differences is that with strict mode enabled JavaScript will throw some types of errors that it would normally just silently ignore. One such error that is normally ignored, but is raised if strict mode is enabled, is our friend the X Is Read-Only TypeError.

At the most basic level strict mode can be enabled by placing the 'use strict'; statement at the top of our script. We won't go into any more details of strict mode's particular behaviors here, but feel free to check out the MDN documentation for more info.

To examine how X Is Read-Only TypeErrors might occur we'll start with a simple working example. Here we declare a book object and output the object to our console. We've accidentally misspelled "Jurassic" during creation so we then update the title property and output the fixed result. Nothing too fancy and everything works as expected, even with strict mode enabled:

// Enable strict mode.
'use strict';

let printError = function (error, explicit) {
console.log(`[${explicit ? 'EXPLICIT' : 'INEXPLICIT'}] ${error.name}: ${error.message}`);
}

try {
// Create book object with a misspelled title.
let book = { title: 'Jurrassic Park', author: 'Michael Crichton' };
// Output book.
console.log(book); // Object {title: "Jurrassic Park", author: "Michael Crichton"}
// Update title with correct spelling.
book.title = 'Jurassic Park';
// Output book.
console.log(book); // Object {title: "Jurassic Park", author: "Michael Crichton"}
} catch (e) {
if (e instanceof TypeError) {
printError(e, true);
} else {
printError(e, false);
}
}

Now let's try a slightly different setup. Here we want to prevent our book object from being altered (i.e. make it immutable), so we'll pass it to the Object.freeze() method which does just that: It prevents properties from being added, removed, or changed. After we have frozen our object we try to update the correct title then output the result:

// Create book object with a misspelled title.
let book = { title: 'Jurrassic Park', author: 'Michael Crichton' };
// Freeze book object.
Object.freeze(book);
// Output book.
console.log(book); // Object {title: "Jurrassic Park", author: "Michael Crichton"}
// Update title with correct spelling.
book.title = 'Jurassic Park';
// Output book.
console.log(book);

Since we have strict mode enabled our attempt to make changes to an existing property of our frozen book object fail and an X Is Read-Only TypeError is thrown:

// CHROME
[EXPLICIT] TypeError: Cannot assign to read only property 'title' of object '#<Object>'

// FIREFOX
[EXPLICIT] TypeError: "title" is read-only

This is one of those instances where strict mode can be very beneficial and serves to make your code more stringent on what modifications it attempts or allows. By freezing our object we're telling JavaScript that this object should now be completely immutable. However, it's important to understand that creating an immutable object only means that that specific object cannot be changed -- even though that single object cannot be changed, we can change the reference of the variable that previously pointed to our old immutable object to a different, mutable object without throwing an error.

To illustrate we'll start with the same example from before:

// Create book object with a misspelled title.
let book = { title: 'Jurrassic Park', author: 'Michael Crichton' };
// Output book.
console.log(book); // Object {title: "Jurrassic Park", author: "Michael Crichton"}
// Freeze book object.
Object.freeze(book);
// Update title with correct spelling.
book.title = 'Jurassic Park'; // Throws TypeError.

We already know that the final line throws an X Is Read-Only TypeError, but we can get around this by simply assigning a new object value to our book variable, thereby changing the memory reference from a previously immutable object to a new, mutable one:

// Create book object with a misspelled title.
let book = { title: 'Jurrassic Park', author: 'Michael Crichton' };
// Output book.
console.log(book); // Object {title: "Jurrassic Park", author: "Michael Crichton"}
// Freeze book object.
Object.freeze(book);
// Assign `book` to new object with corrected `title` property.
book = { title: 'Jurassic Park', author: 'Michael Crichton' };
// Output book.
console.log(book); // Object {title: "Jurassic Park", author: "Michael Crichton"}

While this feels a bit like cheating (and it arguably is depending on your viewpoint and the purpose of your code), it's one particular quirk to remember when using immutable objects, as well as references to said immutable objects. If your goal is to write code that never allows frozen/immutable objects to be modified once instantiated then make sure you never make any assignment statement (x = y) after the initial declaration. While that solution might not work for all projects or meet all business requirements, it's a solid safety practice.

To dive even deeper into understanding how your applications deal with JavaScript Errors, check out the revolutionary Airbrake JavaScript error tracking tool for real-time alerts and instantaneous insight into what went wrong with your JavaScript code.

Written By: Frances Banks