Common Errors Caught by JavaScript Strict Mode

Discover the specific errors JavaScript strict mode catches, from accidental globals to silent assignment failures. Learn each error type with code examples and understand why strict mode prevents them.

JavaScriptbeginner
12 min read

Enabling strict mode does more than flip a switch. It activates a set of enforcement rules that turn silent failures into explicit errors. Each error exists because the behavior it prevents has caused real, hard-to-diagnose bugs in production JavaScript applications.

This tutorial walks through every major error strict mode catches, with runnable code examples showing what happens in normal mode versus strict mode. By the end, you will know exactly what strict mode enforces and why each restriction was added to the language.

ReferenceError: Assignment to Undeclared Variables

This is the single most common bug strict mode prevents. In normal JavaScript, assigning a value to a variable that was never declared with let, const, or var silently creates a property on the global object:

javascriptjavascript
// Normal mode — creates a global variable silently
function processOrder(items) {
  totalPrice = 0;  // Oops — forgot 'let'. Now totalPrice is on window/global
  for (let item of items) {
    totalPrice += item.price;
  }
  return totalPrice;
}
 
processOrder([{ price: 29.99 }, { price: 14.50 }]);
console.log(window.totalPrice); // 44.49 — leaked to global scope!

With strict mode, this assignment immediately throws a ReferenceError:

javascriptjavascript
'use strict';
 
function processOrder(items) {
  totalPrice = 0; // ReferenceError: totalPrice is not defined
  for (let item of items) {
    totalPrice += item.price;
  }
  return totalPrice;
}

Why This Matters

Accidental globals are dangerous because they persist across function calls, can overwrite other variables with the same name, and cause memory leaks in long-running applications. In a large codebase, tracking down where a global was accidentally created can take hours. Strict mode catches the problem instantly at the exact line where the typo or omission occurs.

How to Fix It

Always declare variables with let or const before using them:

javascriptjavascript
'use strict';
 
function processOrder(items) {
  let totalPrice = 0; // Explicit declaration — no error
  for (const item of items) {
    totalPrice += item.price;
  }
  return totalPrice;
}

TypeError: Assignment to Read-Only Properties

JavaScript objects can have properties marked as non-writable using Object.defineProperty. In normal mode, assigning to these properties fails silently. In strict mode, it throws a TypeError:

javascriptjavascript
'use strict';
 
const settings = {};
Object.defineProperty(settings, 'maxRetries', {
  value: 3,
  writable: false,
});
 
settings.maxRetries = 10; // TypeError: Cannot assign to read only property 'maxRetries'

This also applies to built-in read-only globals:

javascriptjavascript
'use strict';
 
undefined = 'something'; // TypeError: Cannot assign to read only property 'undefined'
NaN = 42;                // TypeError: Cannot assign to read only property 'NaN'
Infinity = 0;            // TypeError: Cannot assign to read only property 'Infinity'

Assignments to Getter-Only Properties

If an object has a getter but no setter, strict mode catches the attempt:

javascriptjavascript
'use strict';
 
const user = {
  get fullName() {
    return 'Jane Doe';
  }
};
 
user.fullName = 'John Smith'; // TypeError: Cannot set property fullName which has only a getter

TypeError: Adding Properties to Non-Extensible Objects

When an object is sealed with Object.preventExtensions(), Object.seal(), or Object.freeze(), adding new properties fails silently in normal mode:

javascriptjavascript
'use strict';
 
const config = Object.freeze({
  apiUrl: 'https://api.example.com',
  timeout: 5000,
});
 
config.retryCount = 3;     // TypeError: Cannot add property retryCount, object is not extensible
config.timeout = 10000;     // TypeError: Cannot assign to read only property 'timeout'
Object MethodPrevents AddingPrevents DeletingPrevents Modifying
Object.preventExtensions()YesNoNo
Object.seal()YesYesNo
Object.freeze()YesYesYes

In normal mode, all three of these would fail silently. In strict mode, each violation throws a TypeError that tells you exactly what went wrong.

TypeError: Deleting Undeletable Properties

Some properties, like Object.prototype, are marked as non-configurable and cannot be deleted. Normal mode returns false and continues. Strict mode throws:

javascriptjavascript
'use strict';
 
delete Object.prototype;   // TypeError: Cannot delete property 'prototype'
delete Array.prototype;     // TypeError: Cannot delete property 'prototype'
 
const frozen = Object.freeze({ key: 'value' });
delete frozen.key;          // TypeError: Cannot delete property 'key'

Deleting Plain Variables

In normal mode, delete on a variable silently returns false. In strict mode, it is a SyntaxError:

javascriptjavascript
'use strict';
 
let score = 100;
delete score; // SyntaxError: Delete of an unqualified identifier in strict mode

SyntaxError: Duplicate Function Parameters

Normal mode allows duplicate parameter names, with the last one silently winning. Strict mode prevents this ambiguity:

javascriptjavascript
'use strict';
 
// SyntaxError: Duplicate parameter name not allowed in this context
function createUser(name, age, name) {
  return { name, age };
}

In normal mode, createUser('Alice', 30, 'Bob') would return { name: 'Bob', age: 30 }. The first name parameter is silently overwritten, which is almost never the developer's intent.

How to Fix It

Use distinct parameter names that describe each value:

javascriptjavascript
'use strict';
 
function createUser(firstName, age, lastName) {
  return { firstName, lastName, age };
}

SyntaxError: Octal Literal Syntax

Octal literals (numbers starting with 0) are a legacy feature that causes confusion. The number 0644 looks like six hundred forty-four, but JavaScript interprets it as the octal value 420:

javascriptjavascript
'use strict';
 
let permissions = 0644; // SyntaxError: Octal literals are not allowed in strict mode

How to Fix It

Use the explicit 0o prefix for octal numbers, which makes the intent clear:

javascriptjavascript
'use strict';
 
let permissions = 0o644; // 420 in decimal — explicit and unambiguous
let hex = 0xFF;          // 255 — hexadecimal is fine
let binary = 0b1010;     // 10 — binary is fine
Octal Escape Sequences Too

Strict mode also bans octal escape sequences in strings. '\045' throws a SyntaxError. Use '\x25' (hex) or String.fromCharCode(37) instead.

SyntaxError: The 'with' Statement

The with statement was designed to reduce repetitive object access, but it creates ambiguity about which scope a variable belongs to:

javascriptjavascript
'use strict';
 
const style = { color: 'red', fontSize: '16px' };
 
// SyntaxError: Strict mode code may not include a with statement
with (style) {
  color = 'blue';     // Is this style.color or a global?
  fontSize = '20px';  // Is this style.fontSize or a global?
}

The problem with with is that the JavaScript engine (and developers reading the code) cannot determine at compile time whether color refers to style.color or a variable in an outer scope. This makes optimization impossible and makes code harder to reason about.

How to Fix It

Use destructuring or an explicit variable reference:

javascriptjavascript
'use strict';
 
const style = { color: 'red', fontSize: '16px' };
 
// Option 1: Destructuring
const { color, fontSize } = style;
 
// Option 2: Explicit reference
style.color = 'blue';
style.fontSize = '20px';

TypeError: Restricted 'this' in Functions

In normal mode, this defaults to the global object (window in browsers) when a function is called without an explicit context. Strict mode sets this to undefined:

javascriptjavascript
'use strict';
 
function logContext() {
  console.log(this); // undefined (not window/global)
}
 
logContext();

This change prevents a dangerous pattern where methods accidentally modify the global object:

javascriptjavascript
'use strict';
 
function Timer() {
  this.seconds = 0; // Works when called with 'new'
}
 
// Forgot 'new' — in normal mode, this.seconds goes to window.seconds
// In strict mode, 'this' is undefined, so you get a TypeError immediately
const timer = Timer(); // TypeError: Cannot set properties of undefined

The fix is explicit: always use new with constructor functions, or better yet, use ES6 classes which enforce new automatically.

TypeError: Arguments and Caller Restrictions

Strict mode restricts access to arguments.callee (a reference to the currently executing function) and the caller property:

javascriptjavascript
'use strict';
 
function factorial(n) {
  if (n <= 1) return 1;
  return n * arguments.callee(n - 1); // TypeError: 'caller', 'callee', and 'arguments' properties
                                       // may not be accessed on strict mode functions
}

How to Fix It

Use a named function expression or a standard reference:

javascriptjavascript
'use strict';
 
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1); // Use the function name directly
}
 
console.log(factorial(5)); // 120

SyntaxError: Reserved Words as Identifiers

Strict mode reserves several words that may become keywords in future ECMAScript versions. Using them as variable or function names throws a SyntaxError:

javascriptjavascript
'use strict';
 
let implements = true;  // SyntaxError
let interface = {};     // SyntaxError
let package = 'npm';    // SyntaxError
let private = false;    // SyntaxError
let protected = 0;      // SyntaxError
let public = 'yes';     // SyntaxError
let static = null;      // SyntaxError
let yield = 42;         // SyntaxError

Several of these (static, private, public, protected) are now used in ES6+ class syntax, proving the reservation was forward-thinking.

Complete Error Reference Table

Error TypeTriggerNormal ModeStrict Mode
ReferenceErrorAssigning to undeclared variableCreates globalThrows immediately
TypeErrorAssigning to read-only propertySilent failThrows immediately
TypeErrorAdding property to frozen objectSilent failThrows immediately
TypeErrorDeleting non-configurable propertyReturns falseThrows immediately
TypeErrorAccessing arguments.calleeReturns function refThrows immediately
TypeErrorthis access in plain functionReturns global objectthis is undefined
SyntaxErrorDuplicate parameter namesLast value winsThrows at parse time
SyntaxErrorOctal literal (0644)Interprets as octalThrows at parse time
SyntaxErrorwith statementExecutes normallyThrows at parse time
SyntaxErrorReserved words as identifiersAllows bindingThrows at parse time
SyntaxErrordelete on plain variableReturns falseThrows at parse time
Parse-Time vs Runtime Errors

SyntaxError exceptions are caught at parse time (before any code runs). TypeError and ReferenceError exceptions are caught at runtime (when the violating line executes). Parse-time errors are actually better because they fail fast, before the application starts.

Common Mistakes and How to Avoid Them

Pitfalls When Adopting Strict Mode

These mistakes frequently appear when developers enable strict mode in existing projects.

Enabling strict mode without running tests. Adding 'use strict' to a file that relies on implicit globals or sloppy this behavior will cause runtime errors. Always run your test suite after enabling strict mode on any file.

Confusing TypeError with a code bug. When strict mode throws a TypeError for assigning to a frozen property, the error is telling you the design is working correctly. The property was intentionally made read-only. If you need to modify it, revisit the data model instead of removing strict mode.

Ignoring SyntaxError messages. Because SyntaxError happens at parse time, the entire script fails to load. A single octal literal or duplicate parameter in a large file will prevent the whole file from executing. Check your browser console for parse errors after enabling strict mode.

Assuming arrow functions fix all this problems. Arrow functions inherit this from their lexical scope, which solves many issues. But strict mode's undefined behavior for plain functions still applies if you use function declarations as callbacks in strict-mode code.

Next Steps

Enable strict mode in your current project

Add 'use strict' to one file at a time. Fix every error that surfaces, then move to the next file. This incremental approach prevents breaking your entire application at once.

Learn JavaScript debugging techniques

Understanding basic debugging tips will help you trace strict mode errors efficiently using browser DevTools.

Configure ESLint strict mode rules

Set up ESLint with the strict rule to automatically flag files missing the 'use strict' directive. The "global" option enforces script-level strict mode.

Explore JavaScript console methods

Use console methods to log and inspect error objects thrown by strict mode. console.error and console.trace are especially useful for tracking down violations.

Rune AI

Rune AI

Key Insights

  • Accidental globals are the top catch: strict mode turns the most common JavaScript bug (assigning to undeclared variables) into an immediate ReferenceError
  • Silent failures become visible: read-only assignments, frozen object modifications, and undeletable property deletions all throw TypeError instead of failing quietly
  • Parse-time errors fail fast: SyntaxError for octal literals, duplicate parameters, and with statements prevents the script from executing at all, catching issues before runtime
  • Incremental adoption works: enable strict mode one function or file at a time, fix each error, and expand gradually across the codebase
  • Modern JavaScript is strict by default: ES6 modules and class bodies enforce strict mode automatically, making explicit 'use strict' unnecessary in modern toolchains
RunePowered by Rune AI

Frequently Asked Questions

Does strict mode catch all JavaScript bugs?

No. Strict mode catches a specific set of silent failures and ambiguous syntax patterns. It does not catch logic errors, race conditions, or issues like accessing properties on `null`. Use TypeScript, ESLint, and comprehensive testing alongside strict mode for broader coverage.

Will strict mode break my existing code?

It depends on your code. If your code relies on implicit global variables, the `with` statement, octal literals, or loose `this` behavior, enabling strict mode will throw errors. The fix is straightforward for each case, but you should test before deploying.

Are strict mode errors recoverable with try-catch?

Runtime errors (`TypeError`, `ReferenceError`) can be caught with try-catch. Parse-time errors (`SyntaxError` from octal literals, duplicate parameters, or `with` statements) cannot be caught because the script fails before it starts executing.

Do Node.js applications need strict mode?

If your Node.js project uses ES modules (`.mjs` files or `"type": "module"` in `package.json`), strict mode is automatic. For CommonJS modules (`.cjs` or default `.js`), adding `'use strict'` is still recommended and is standard practice in most Node.js projects.

Is there a way to make strict mode the default everywhere?

Yes, by using ES6 modules. When every file in your project uses `import`/`export` syntax, all code runs in strict mode automatically. Most modern frameworks and build tools (Next.js, Vite, Webpack) already configure module-based builds.

Can strict mode affect performance?

In most cases, strict mode improves performance slightly. It eliminates the need for the engine to check for ambiguous constructs like `with` scope resolution, implicit global creation, and `arguments` object mirroring. V8, SpiderMonkey, and JavaScriptCore all benefit from the stricter guarantees.

Conclusion

JavaScript strict mode catches a precise set of errors that trip up developers in real projects: accidental globals from typos, silent failures on read-only assignments, ambiguous syntax like duplicate parameters and octal literals, and unsafe patterns like arguments.callee and the with statement. Each restriction exists because the normal-mode behavior has caused documented, recurring bugs in production codebases.