Some operations do not accept just any number. Asking for a hundred and fifty decimal digits, or an array of negative size, makes no sense, and the language says so rather than guessing.
It is a rare error compared with the others, yet its best-known message has almost nothing to do with the bounds of a number.
Definition
A RangeError is thrown when a value falls outside the interval the requested operation allows. The type is right, the value is not.
const cases = [
() => new Array(-1),
() => (1.5).toFixed(101),
() => (255).toString(40),
() => "ab".repeat(-1),
];
for (const f of cases) {
try { f(); } catch (err) { console.log(err.name, "|", err.message); }
}
// RangeError | Invalid array length
// RangeError | toFixed() digits argument must be between 0 and 100The message always names the expected bound, which makes the fix immediate once the offending call has been identified.
The native cases worth knowing
| Call | Accepted interval |
|---|---|
new Array(n) | An integer from 0 to roughly four billion |
toFixed(n) | From 0 to 100 digits |
toString(base) | A base from 2 to 36 |
repeat(n) | A finite number, zero or above |
Date also produces a RangeError, with the message Invalid time value, when the standardized format of an uninterpretable date is requested. That is the most common case in practice, usually triggered by a malformed string received from an interface.
Maximum call stack size exceeded
Here is the message everyone has already seen, and it really is a RangeError. The bound exceeded is not that of a number, it is the maximum depth of the call stack.
function countDown(n) {
return n === 0 ? 0 : 1 + countDown(n - 1); // no guard below zero
}
try {
countDown(-1); // the stopping condition is never reached
} catch (err) {
console.log(err.name, "|", err.message);
// RangeError | Maximum call stack size exceeded
}The cause is almost always a recursion with no proper stopping condition, or a structure that contains itself. Check the condition before suspecting the depth.
A legitimate but very deep recursion hits the same limit. Rewriting it as a loop removes the problem for good, whereas raising the stack size merely postpones the failure and depends on the environment.
Frequently asked questions
What is the maximum stack depth?
No specification sets it, and it varies with the engine, the version and the size of each call's variables. Never build an algorithm on an assumed depth: if the number of calls depends on input data, a loop is the safe choice.
Should a RangeError be caught?
As with a TypeError, it usually signals a defect to fix. One exception: validating a date received from outside, where failure belongs to the normal path and deserves a try with a clear message for the user.
How do you validate a date before formatting it?
By testing the result of getTime(): a date that cannot be interpreted hands back a value that is not a number. A check with Number.isNaN ahead of any formatting avoids the error and lets you show an understandable message instead of a breakdown.