error python

Python RecursionError

Understanding Python RecursionError - raised when the maximum recursion depth is exceeded, usually indicating infinite recursion.

What It Means

RecursionError is raised when the maximum recursion depth is exceeded. Python has a default recursion limit (usually 1000) to prevent stack overflow crashes. This error almost always indicates infinite or unbounded recursion — a function calling itself without a proper base case.

Common Causes

  • Missing or incorrect base case in a recursive function
  • Infinite recursion due to logic errors
  • Circular __repr__, __str__, or __eq__ methods
  • Circular property access
  • Recursive data structures being serialized
  • Accidental recursion from overridden methods calling themselves

How to Fix

Add a proper base case

# Bad: no base case
def factorial(n):
    return n * factorial(n - 1)  # Never stops!

# Good: add a base case
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

Convert to iteration

# Recursive version (risky for large inputs)
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

# Iterative version (no recursion limit)
def fibonacci(n):
    if n <= 1:
        return n
    a, b = 0, 1
    for _ in range(2, n + 1):
        a, b = b, a + b
    return b

# Recursive tree traversal → iterative with a stack
def traverse_iterative(root):
    stack = [root]
    while stack:
        node = stack.pop()
        process(node)
        stack.extend(node.children)

Fix circular method calls

# Bad: __repr__ calls itself indirectly
class Node:
    def __init__(self, value, parent=None):
        self.value = value
        self.parent = parent

    def __repr__(self):
        return f"Node({self.value}, parent={self.parent})"  # Infinite loop!

# Good: avoid circular references in __repr__
class Node:
    def __repr__(self):
        parent_val = self.parent.value if self.parent else None
        return f"Node({self.value}, parent_value={parent_val})"

Fix accidental recursion in property setters

# Bad: property setter calls itself
class User:
    @property
    def name(self):
        return self.name  # Calls the property getter again!

    @name.setter
    def name(self, value):
        self.name = value  # Calls the setter again!

# Good: use a private attribute
class User:
    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

Increase recursion limit (use sparingly)

import sys

# Check current limit
print(sys.getrecursionlimit())  # Default: 1000

# Increase limit (use with caution)
sys.setrecursionlimit(5000)

# Note: this doesn't increase the actual stack size
# For very deep recursion, also increase the thread stack size:
import threading
threading.stack_size(67108864)  # 64MB stack

Use memoization to reduce recursion depth

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

# Now fibonacci(1000) works without hitting the recursion limit
# because previously computed values are cached

Tail recursion workaround

# Python doesn't optimize tail recursion, but you can convert manually
# Recursive:
def sum_list(lst, acc=0):
    if not lst:
        return acc
    return sum_list(lst[1:], acc + lst[0])  # RecursionError for large lists

# Iterative equivalent:
def sum_list(lst):
    acc = 0
    for item in lst:
        acc += item
    return acc