JavaScript Strict Mode Non-Writable Properties

In JavaScript, strict mode changes how the runtime engine handles attempts to modify non-writable properties, transforming silent failures into explicit runtime exceptions. While non-strict mode ignores assignments to read-only properties without warning, strict mode immediately throws a TypeError. This article explains the technical mechanics of non-writable properties, contrasts behavior across both execution modes, and outlines the common scenarios where these errors occur.

Non-Strict Mode: Silent Failure

In non-strict (or “sloppy”) mode, when a script attempts to overwrite a property whose writable attribute is set to false, the JavaScript engine ignores the operation. The assignment expression evaluates to the assigned value, but the underlying property value remains unchanged.

// Non-strict mode
const user = {};
Object.defineProperty(user, "role", {
  value: "Admin",
  writable: false
});

user.role = "Editor"; // Fails silently
console.log(user.role); // Output: "Admin"

This silent failure makes debugging difficult, as the code continues executing as if the mutation succeeded.

Strict Mode: Explicit TypeError

When strict mode is enabled via the "use strict"; directive, the engine enforces strict assignment semantics. Attempting to write to a read-only property throws a TypeError, halting execution unless caught in a try...catch block.

"use strict";

const user = {};
Object.defineProperty(user, "role", {
  value: "Admin",
  writable: false
});

user.role = "Editor"; 
// Uncaught TypeError: Cannot assign to read only property 'role' of object '#<Object>'

Common Scenarios Triggering the Error

Strict mode alters assignment behavior across several types of non-writable targets:

  1. Explicitly Configured Properties: Properties defined using Object.defineProperty() or Object.defineProperties() with writable: false.
  2. Getter-Only Accessors: Object properties defined with a get function but no corresponding set function.
  3. Frozen Objects: Properties on objects processed with Object.freeze(), which automatically sets writable: false and configurable: false on all existing own properties.
  4. Built-in Global Constants: Global non-writable identifiers such as undefined, NaN, and Infinity. In strict mode, statements like undefined = 5; throw a TypeError.

By surfacing these invalid operations immediately at runtime, strict mode prevents subtle state bugs and ensures predictable object immutability.