RangeError: Maximum call stack size exceeded
A function is calling itself (or calling another function that calls it back) infinitely until the call stack runs out of space.
Fix 1: Missing Base Case in Recursion
// ❌ No base case — calls itself forever
function countdown(n) {
console.log(n);
countdown(n - 1);
}
// ✅ Add a base case
function countdown(n) {
if (n <= 0) return; // Stop here
console.log(n);
countdown(n - 1);
}
Fix 2: Infinite useEffect Loop (React)
// ❌ setState triggers re-render, which triggers useEffect, which triggers setState...
useEffect(() => {
setCount(count + 1);
});
// ✅ Add a dependency array
useEffect(() => {
setCount(count + 1);
}, []); // Run once
See also: React too many re-renders fix
Fix 3: Circular JSON.stringify
// ❌ Object references itself
const obj = {};
obj.self = obj;
JSON.stringify(obj); // 💥 Maximum call stack
// ✅ Use a replacer to handle circular references
function safeStringify(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) return '[Circular]';
seen.add(value);
}
return value;
});
}
Fix 4: Getter/Setter Calling Itself
// ❌ Getter calls itself
const obj = {
get name() {
return this.name; // 💥 Calls the getter again
}
};
// ✅ Use a backing property
const obj = {
_name: 'Alice',
get name() {
return this._name;
}
};
Fix 5: Two Functions Calling Each Other
// ❌ Mutual recursion without termination
function isEven(n) {
return isOdd(n - 1);
}
function isOdd(n) {
return isEven(n - 1);
}
// ✅ Add base cases to both
function isEven(n) {
if (n === 0) return true;
if (n < 0) return false;
return isOdd(n - 1);
}
function isOdd(n) {
if (n === 0) return false;
if (n < 0) return false;
return isEven(n - 1);
}
Fix 6: Convert Recursion to Iteration
If your recursion is too deep (even with a base case), convert to a loop:
// ❌ Deep recursion (might overflow for large n)
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// ✅ Iterative version
function factorial(n) {
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
}
Debugging
Add a counter to find the runaway function:
let calls = 0;
function suspect() {
calls++;
if (calls > 1000) throw new Error(`Called ${calls} times — probably infinite`);
// ... rest of function
}