A silent error is a mistake that does not throw anything. The program keeps running, but with wrong data, and you may not notice until much later. The reason is history: the first version of JavaScript (1995) had no try...catch (it arrived in 1999), so the language was designed to keep going rather than stop. Knowing where silent errors hide is half of debugging.
Impossible math gives a special number instead of an error:
console.log(1 / 0, -1 / 0);
console.log(parseInt("abc"), "abc" * 5);
console.log(Math.max()); // no arguments at all
Infinity and NaN then spread through every calculation that uses them (JS NaN). Check with Number.isFinite(x) before trusting a result.
A single = inside an if assigns instead of comparing. The assignment gives back the new value, so the condition is truthy and the block always runs:
let result = "Not Active.";
let isActive = false;
if (isActive = true) { // assignment, not comparison
result = "Active!";
}
console.log(result, isActive);
Two bugs in one: the block ran when it should not have, and isActive itself was changed to true. JavaScript cannot flag this, because assigning inside a condition is legal (and occasionally intended).
let result = "Active!"; inside the if block. That let creates a new block-scoped variable, so the outer result stays "Not Active." and the example hides the very bug it is meant to show. A silent bug inside a silent-error example.
Reading a property that does not exist, an array position past the end, or the result of a function that forgot to return all give undefined, with no error:
const user = { name: "Ava" };
console.log(user.nmae); // typo in the property name
const scores = [90, 85];
console.log(scores[2]); // only positions 0 and 1 exist
function double(n) { n * 2; } // forgot return
console.log(double(4));
The error usually shows up later and somewhere else, when you try to use that undefined: user.nmae.length is a TypeError, far from the typo that caused it.
Some assignments are silently ignored: setting a property on a primitive, or changing an object that was frozen with Object.freeze:
let word = "cat";
word.color = "orange";
console.log(word.color);
const settings = Object.freeze({ volume: 5 });
settings.volume = 11;
console.log(settings.volume);
Strict mode (JS Strict Mode) turns these into real errors, which is one of the best reasons to use it:
"use strict";
const settings = Object.freeze({ volume: 5 });
settings.volume = 11;
An impossible date does not fail. JavaScript rolls the extra days into the next month (JS Date Set), and text it cannot read becomes an "Invalid Date" object:
const d = new Date(2026, 1, 30); // February 30th
console.log(d.getMonth() + 1, d.getDate());
console.log(String(new Date("2026-13-45")));
JS Type Coercion is full of silent errors: "5" + 2 is "52", [10, 9, 1].sort() sorts as text, and == treats 0, "", and false as equal. None of them throw.
You cannot make JavaScript complain about everything, but you can catch most silent errors early:
| "use strict" | Failed assignments and undeclared variables throw |
| === and !== | No surprise conversions in comparisons |
| Number.isFinite / Number.isNaN | Stop NaN and Infinity at the source |
| Check for undefined | Catch typos and missing data before using them |
| throw your own errors | Turn "impossible" data into a loud failure |
The last row is the most powerful. When a function receives data that would silently produce garbage, throw an error instead (JS Error Statements covers throw in full):
function average(list) {
if (list.length === 0) {
throw new RangeError("Cannot average an empty list");
}
let sum = 0;
for (const n of list) sum += n;
return sum / list.length;
}
console.log(average([90, 80]));
console.log(average([]));
Now the mistake stops the program right where it happened, with a message that says what went wrong, instead of an average of NaN quietly showing up on a report card.
What does this log?
let count = 0;
if (count = 5) console.log("five!");
console.log(count);
five! then 5. The single = assigns 5, which is truthy, so the if runs, and count has been changed.Which of these does not throw an error?
null.xundeclaredVariable1 / 0(5)()Infinity. A is a TypeError, B a ReferenceError, and D a TypeError (5 is not a function).Why does JavaScript prefer to keep running with a wrong value instead of stopping with an error?
try...catch, so a thrown error could not be handled and would simply break the page. The language was designed to keep going, and those rules cannot change without breaking old websites.NaN, Infinity, or undefinedisActive = true bug, then fix it with ==="use strict", and comparethrow to a function of your own so bad input fails loudly