Card 05/ 08
A Base Case the Recursion Never Reaches
A missing base case, or a step that skips past it, runs until the call stack is full.
A recursive function stops only when a call reaches its base case, the input it answers without calling itself, so a base case that is missing, or that the calls step over, never stops the function. This card covers the two forms of that mistake, and the error Python, Java and TypeScript raise when the call stack, which holds one frame for every unfinished call, runs out of room.
The symptom is an error after a long pause, or at once, from a function that looks finished. The trigger is either no base case at all, or a recursive step that can jump past the base case. count_down below has a base case, n == 0, and steps down by 2. From 6 it visits 4, 2 and 0 and stops. From 5 it visits 3, 1, −1, −3 and so on: n is never exactly 0, so the base case is never met. The mechanism is that nothing else stops a recursion. Each call adds a frame and none returns, so the stack fills, and the language raises an error. The fix compares with <=, so any n at or below 0 ends the calls. The listing ran both versions, and the highlighted lines are the two base cases.
def count_down(n):
if n == 0:
return "lift-off"
return count_down(n - 2)
def count_down_fixed(n):
if n <= 0:
return "lift-off"
return count_down_fixed(n - 2)
print("count_down(6):", count_down(6))
try:
print("count_down(5):", count_down(5))
except RecursionError as error:
print("count_down(5):", type(error).__name__ + ":", error)
print("count_down_fixed(5):", count_down_fixed(5))count_down(6): lift-off
count_down(5): RecursionError: maximum recursion depth exceeded
count_down_fixed(5): lift-offEach language names the failure differently, and only Python counts frames. The table gives what a run of the same function, called to a depth of 1,000,000, raised in each, with the limit behind it. Java and Node have no frame count: they stop when the memory set aside for the stack is used up, and on Node that memory is set by V8, the JavaScript engine inside it, so how deep a function can go depends on how much each of its frames holds.
| Language | Error raised | Default limit, or why there is none |
|---|---|---|
| Python 3.14.8 | RecursionError | 1000 frames, read with sys.getrecursionlimit() and changed with sys.setrecursionlimit() |
| Java 25.0.4.1 | StackOverflowError | No frame count: the thread's stack size decides, set with the java command's -Xss option or when a thread is created; depth 1,000,000 failed on the main thread and finished on a thread given 1 GiB |
| TypeScript on Node 24.22.0 | RangeError, Maximum call stack size exceeded | No frame count: V8's stack size decides, 984 KB unless node --stack-size changes it; a one-line function reached about 10,000 calls in a run |
Raising the limit does not fix either form. A function with no base case fills any stack, however large, and a raised limit only makes it fail later. Check two things instead: that every input has a base case it will reach, and that every recursive step moves strictly closer to it. A step of 2, a step that can overshoot, or a step that sometimes keeps the input the same size each breaks the second check.
← → move through sections and cards