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.
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:
// 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:
'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:
'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:
'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:
'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:
'use strict';
const user = {
get fullName() {
return 'Jane Doe';
}
};
user.fullName = 'John Smith'; // TypeError: Cannot set property fullName which has only a getterTypeError: 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:
'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 Method | Prevents Adding | Prevents Deleting | Prevents Modifying |
|---|---|---|---|
Object.preventExtensions() | Yes | No | No |
Object.seal() | Yes | Yes | No |
Object.freeze() | Yes | Yes | Yes |
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:
'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:
'use strict';
let score = 100;
delete score; // SyntaxError: Delete of an unqualified identifier in strict modeSyntaxError: Duplicate Function Parameters
Normal mode allows duplicate parameter names, with the last one silently winning. Strict mode prevents this ambiguity:
'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:
'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:
'use strict';
let permissions = 0644; // SyntaxError: Octal literals are not allowed in strict modeHow to Fix It
Use the explicit 0o prefix for octal numbers, which makes the intent clear:
'use strict';
let permissions = 0o644; // 420 in decimal — explicit and unambiguous
let hex = 0xFF; // 255 — hexadecimal is fine
let binary = 0b1010; // 10 — binary is fineOctal 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:
'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:
'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:
'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:
'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 undefinedThe 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:
'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:
'use strict';
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // Use the function name directly
}
console.log(factorial(5)); // 120SyntaxError: 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:
'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; // SyntaxErrorSeveral of these (static, private, public, protected) are now used in ES6+ class syntax, proving the reservation was forward-thinking.
Complete Error Reference Table
| Error Type | Trigger | Normal Mode | Strict Mode |
|---|---|---|---|
ReferenceError | Assigning to undeclared variable | Creates global | Throws immediately |
TypeError | Assigning to read-only property | Silent fail | Throws immediately |
TypeError | Adding property to frozen object | Silent fail | Throws immediately |
TypeError | Deleting non-configurable property | Returns false | Throws immediately |
TypeError | Accessing arguments.callee | Returns function ref | Throws immediately |
TypeError | this access in plain function | Returns global object | this is undefined |
SyntaxError | Duplicate parameter names | Last value wins | Throws at parse time |
SyntaxError | Octal literal (0644) | Interprets as octal | Throws at parse time |
SyntaxError | with statement | Executes normally | Throws at parse time |
SyntaxError | Reserved words as identifiers | Allows binding | Throws at parse time |
SyntaxError | delete on plain variable | Returns false | Throws 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
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
TypeErrorinstead of failing quietly - Parse-time errors fail fast:
SyntaxErrorfor octal literals, duplicate parameters, andwithstatements 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
Frequently Asked Questions
Does strict mode catch all JavaScript bugs?
Will strict mode break my existing code?
Are strict mode errors recoverable with try-catch?
Do Node.js applications need strict mode?
Is there a way to make strict mode the default everywhere?
Can strict mode affect performance?
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.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.