Every function call consumes a frame on the call stack, and Python caps the stack (1000 frames by default) to fail loudly instead of crashing. RecursionError means the cap was hit: a function kept calling itself, or a cycle of functions kept calling each other, without ever reaching the case that stops. In practice it is a logic bug, a missing or unreachable base case, far more often than genuinely deep data.
def countdown(n):
print(n)
countdown(n - 1) # no stopping case: calls forever
Traceback (most recent call last):
File "main.py", line 3, in countdown
RecursionError: maximum recursion depth exceeded
# fixed: give it a base case that is actually reached
def countdown(n):
if n <= 0:
return
print(n)
countdown(n - 1)
__repr__ that formats itself, or a wrapper that calls the function it replaced all recurse without looking recursive.sys.setrecursionlimit(10000) plus a larger thread stack (threading.stack_size) for truly deep structures. Raising it to silence an infinite recursion converts a clean exception into a hard interpreter crash.sys.setrecursionlimit without first proving the recursion terminates is how a debuggable error becomes a segfault that kills the whole process.Mutual recursion (A calls B calls A) with a data-dependent exit can cycle forever on particular inputs, often data with a reference loop (a category whose parent is itself). Validate the input graph for cycles when the recursion follows links in data.
What is Python's default recursion limit? 1000 frames, readable with sys.getrecursionlimit(). It counts all nested calls, not just the recursive one, so deep frameworks leave somewhat less room than the number suggests.
Is recursion just bad in Python? No; shallow recursion over naturally recursive data (trees of modest depth, divide and conquer) is clear and safe. Python lacks tail-call optimization, so recursion whose depth grows with input size is the pattern to convert to loops.