All posts
javascriptrangeerrordebugging

Maximum call stack size exceeded — What It Means and How to Fix It

"Maximum call stack size exceeded" explained — why it happens, a real code example that triggers it, and the exact fix.

SR

Suhail Roushan

August 6, 2026

·
3 min read
·
0 views

"Maximum call stack size exceeded" means your JavaScript program has exhausted the call stack's fixed memory limit, usually from unbounded recursion or an infinite synchronous loop.

What "Maximum call stack size exceeded" Means

The call stack is a finite LIFO (last-in, first-out) structure that tracks function calls. Every nested call pushes a frame; when the stack exceeds its limit (typically ~10,000 frames in V8, which powers Chrome and Node.js), the runtime throws this RangeError. It's not a syntax error — your code is syntactically valid, but the execution path never terminates.

Why It Happens

Three real causes dominate:

  1. Unbounded recursion — a function calls itself without a proper base case or with a base case that never becomes true.
  2. Infinite synchronous loops — not for loops (those don't use the stack), but recursive functions masquerading as loops, like a while(true) implemented via self-calls.
  3. Deeply nested data structures — e.g., a circular JSON object passed to JSON.stringify or a recursive traversal of a cyclic graph without a visited set.

Example Code That Triggers It

Here's a minimal, runnable snippet that throws the error in Node.js or any browser console:

function countDown(n) {
  // No base case — n keeps decreasing forever
  return countDown(n - 1);
}

countDown(10);
// RangeError: Maximum call stack size exceeded

This crashes because countDown calls itself with no termination condition. Each call adds a frame; after ~10,000 frames, V8 throws.

How to Fix It

Add a base case and convert to iteration where possible:

function countDown(n) {
  if (n <= 0) return; // base case stops recursion
  console.log(n);
  countDown(n - 1);
}

// Or better — avoid recursion entirely for linear work:
function countDownIterative(n) {
  for (let i = n; i > 0; i--) {
    console.log(i);
  }
}

The fix works because the base case guarantees the stack eventually unwinds. The iterative version sidesteps the stack entirely, using constant memory regardless of n.

Common Mistakes That Cause This

Mistake 1: Forgetting to update the recursive argument. Developers write return fib(n) instead of return fib(n - 1) + fib(n - 2), creating infinite recursion. Always verify the recursive call moves toward the base case.

Mistake 2: Recursing on mutable shared state. A function that mutates a global counter but checks it after the recursive call — the check never runs because the stack overflows first. Check conditions before recursing, not after.

When Should You Worry About This?

Worry immediately if it appears in production code — it's a crash, not a warning. But if it shows up during development, it's almost always a logic bug, not a resource problem. Legitimate deep recursion (e.g., traversing a 50,000-node tree) should be rewritten iteratively or with an explicit stack array. If you're using React or Next.js, this error often surfaces in useEffect with recursive state updates — check for missing dependency arrays that cause infinite re-renders.

First thing to check next time: trace your recursive function's base case with a console.log at the top — if it never logs the exit condition, that's your bug.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch