How to increase the recursion limit in Python
Learn to increase Python's recursion limit. This guide covers methods, tips, real-world applications, and debugging common errors.

Python's recursion limit is a safeguard against stack overflows from deep function calls. For certain complex algorithms, you may need to adjust this default setting to execute your code.
In this article, you’ll learn techniques to safely increase the limit using sys.setrecursionlimit(). You'll also explore real-world applications, tips, and debugging advice to manage recursion effectively.
Using sys.setrecursionlimit() for basic limit adjustment
import sys
print(f"Default recursion limit: {sys.getrecursionlimit()}")
sys.setrecursionlimit(3000)
print(f"New recursion limit: {sys.getrecursionlimit()}")--OUTPUT--Default recursion limit: 1000
New recursion limit: 3000
The sys module gives you direct access to the Python interpreter's settings. The example code uses two of its functions to manage the recursion depth:
sys.getrecursionlimit()fetches the current limit, which is often 1000 by default.sys.setrecursionlimit()sets a new, higher limit to prevent aRecursionError.
Increasing the limit tells the interpreter to reserve more memory for the call stack. This accommodates the longer chain of function calls required by algorithms that legitimately need deeper recursion, like processing a deeply nested tree structure.
Basic approaches to recursion limit management
While sys.setrecursionlimit() offers a quick fix, more advanced strategies provide safer and more flexible control over your application's recursion depth.
Checking the current recursion limit and testing depth
import sys
def recursive_function(n):
if n <= 0:
return
recursive_function(n-1)
print(f"Current recursion limit: {sys.getrecursionlimit()}")
try:
recursive_function(1100) # Will exceed default limit
except RecursionError as e:
print(f"Error: {e}")--OUTPUT--Current recursion limit: 1000
Error: maximum recursion depth exceeded while calling a Python object
This example demonstrates how to proactively test your code against the current recursion limit. By wrapping the function call in a try...except block, you can anticipate and manage a RecursionError without crashing your application.
- The
recursive_functionis called with1100, a value intentionally chosen to exceed the default limit of1000. - Instead of crashing, the program catches the error and prints a message, showing a controlled failure.
This approach helps you confirm if your algorithm genuinely needs a higher limit or if there's a bug causing infinite recursion.
Creating a context manager for temporary limit changes
import sys
from contextlib import contextmanager
@contextmanager
def temporary_recursion_limit(new_limit):
old_limit = sys.getrecursionlimit()
sys.setrecursionlimit(new_limit)
try:
yield
finally:
sys.setrecursionlimit(old_limit)
with temporary_recursion_limit(2000):
print(f"Inside context: {sys.getrecursionlimit()}")
print(f"Outside context: {sys.getrecursionlimit()}")--OUTPUT--Inside context: 2000
Outside context: 1000
A context manager offers a more robust way to handle recursion limits. It confines the change to a specific block of code using a with statement. This approach is safer because it guarantees the original limit is restored afterward—even if an error happens inside the block—preventing unintended side effects elsewhere in your application.
- The
@contextmanagerdecorator from thecontextlibmodule turns a generator function into a reusable context manager. - A
try...finallyblock is crucial. It sets the new limit,yields control to thewithblock, and then always restores the old limit in thefinallyclause.
Using threading stack size to support deeper recursion
import sys
import threading
print(f"Default thread stack size: {threading.stack_size()}")
# Increase thread stack size (in bytes)
threading.stack_size(2**27) # 128MB stack
print(f"New thread stack size: {threading.stack_size()}")
# Now threads can handle deeper recursion--OUTPUT--Default thread stack size: 0
New thread stack size: 134217728
For multithreaded applications, you can increase the stack size for new threads to support deeper recursion. This method allocates more physical memory for a thread's call stack, which is a more robust solution than simply raising the interpreter's limit with sys.setrecursionlimit().
- The
threading.stack_size()function lets you set the stack size in bytes for any threads created afterward. - A larger stack provides the necessary memory to prevent a stack overflow crash when a thread runs a deeply recursive function.
- A default value of
0means the system's default stack size is used.
Advanced recursion management techniques
Moving beyond simple limit adjustments, advanced strategies involve redesigning your recursive logic itself for more robust and efficient execution.
Converting recursion to iteration with a stack
def factorial_recursive(n):
return 1 if n <= 1 else n * factorial_recursive(n-1)
def factorial_iterative(n):
result = 1
stack = list(range(2, n+1))
while stack:
result *= stack.pop()
return result
print(f"Recursive: {factorial_recursive(5)}")
print(f"Iterative: {factorial_iterative(5)}")--OUTPUT--Recursive: 120
Iterative: 120
You can bypass Python's recursion limit by converting a recursive function into an iterative one. This approach replaces the interpreter's call stack with a manual stack that you manage yourself, often using a simple list. This completely avoids the risk of a RecursionError.
- The
factorial_iterativefunction demonstrates this by building astackof numbers to process. - A
whileloop then repeatedly takes a number from the stack usingpop()and multiplies it, achieving the same result without deep function calls.
Creating a decorator for function-specific limit adjustment
import sys
from functools import wraps
def with_increased_recursion(limit=3000):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
old_limit = sys.getrecursionlimit()
sys.setrecursionlimit(limit)
try:
return func(*args, **kwargs)
finally:
sys.setrecursionlimit(old_limit)
return wrapper
return decorator
@with_increased_recursion(limit=1500)
def deep_recursion(n):
return n if n <= 0 else deep_recursion(n-1) + 1--OUTPUT--# No output shown - the decorator allows the function to use a higher limit when called
A decorator offers a clean, reusable way to apply a temporary recursion limit to a specific function. It’s more targeted than a context manager because you apply it directly to the function definition, making the change self-contained and clear.
- The
@with_increased_recursiondecorator takes a customlimit. - It uses a
try...finallyblock to safely set the new limit before your function runs and restore the old one afterward. - Using
@wrapsfrom thefunctoolsmodule preserves the original function's metadata, which helps with debugging.
This approach neatly packages the logic, keeping your function's code clean.
Implementing tail-call optimization for recursive functions
import functools
def tail_call_optimized(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
f = sys._getframe()
if f.f_back and f.f_back.f_back and f.f_back.f_code == f.f_code:
raise TailRecursionException(args, kwargs)
result = func(*args, **kwargs)
while True:
try:
return result
except TailRecursionException as e:
result = func(*e.args, **e.kwargs)
return wrapper--OUTPUT--# No output shown - the decorator transforms recursive calls into iteration
Python doesn't natively support tail-call optimization, but this decorator cleverly simulates it. It transforms deep recursion into an iterative loop, effectively bypassing Python's recursion limit. This is a powerful way to handle algorithms that would otherwise cause a stack overflow.
- The decorator uses
sys._getframe()to inspect the call stack and detect when a function calls itself. - When a tail call occurs, it raises a custom
TailRecursionExceptioninstead of making a new function call. - An outer
whileloop catches this exception and restarts the function with the new arguments, turning recursion into iteration.
Move faster with Replit
Replit is an AI-powered development platform that transforms natural language into working applications. You can describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.
For the advanced recursion techniques we've covered, Replit Agent can turn them into production-ready tools. It can take a concept that requires deep recursion and build a functional application around it.
- Build a file system analyzer that recursively scans directories to map out a dependency tree, handling deeply nested project structures without crashing.
- Create a syntax tree visualizer that parses code and displays its nested structure, using an iterative approach to handle large source files.
- Deploy a graph traversal tool for social network analysis, using a custom decorator to safely manage recursion depth while finding connections in large datasets.
Describe your application idea, and Replit Agent will write the code, test it, and handle deployment, turning your concept into a working tool right in your browser.
Common errors and challenges
Managing Python's recursion limit introduces subtle challenges, from unintended side effects to sudden application crashes that are hard to debug.
- Forgetting to reset the limit. A change made with
sys.setrecursionlimit()is global. If you don’t restore the original value, it can cause unexpected behavior in other parts of your application or in third-party libraries that depend on the default setting. This is why using a context manager or decorator is the safest approach, as they automatically handle cleanup for you. - Avoiding system crashes. Setting the limit too high doesn't give your program infinite memory—it just pushes the boundary. If your recursion goes too deep, you won't get a neat Python
RecursionError. Instead, you'll likely exhaust the C stack, causing a segmentation fault that crashes the entire interpreter without a chance to recover. - Detecting infinite recursion. A
RecursionErroris often a helpful sign of a bug, not just a low limit. If your function never reaches its base case, it will recurse forever. To debug this, you can add a depth-tracking parameter to your function and print its value on each call to see if it's growing uncontrollably.
Forgetting to reset the sys.setrecursionlimit() after processing
When you change the recursion limit with sys.setrecursionlimit(), the change is global. If you don't reset it, the new limit persists throughout your application, potentially causing issues in unrelated code. The following example shows how this oversight can happen.
import sys
def process_deep_data():
# Increase limit for processing
sys.setrecursionlimit(5000)
process_nested_structure()
# Never resets the limit!
Because process_deep_data never resets the recursion limit, the elevated setting remains active globally after the function finishes. The following code demonstrates how this oversight can cause problems in an unrelated part of the application.
import sys
def process_deep_data():
old_limit = sys.getrecursionlimit()
try:
sys.setrecursionlimit(5000)
process_nested_structure()
finally:
sys.setrecursionlimit(old_limit)
The key is the try...finally block. It guarantees the original limit is restored because the finally clause always runs, even if an error occurs. This prevents the change from affecting other parts of your application. You should use this pattern whenever you modify global settings like the recursion limit, especially in library code or large projects where functions might be used in unexpected ways. This approach ensures your code is robust and self-contained.
Avoiding system crashes when setting sys.setrecursionlimit() too high
Raising the recursion limit with sys.setrecursionlimit() seems like an easy fix, but setting it too high is dangerous. It bypasses Python's safety net, risking a hard system crash instead of a manageable RecursionError. The code below demonstrates this exact scenario.
import sys
# Dangerously high recursion limit
sys.setrecursionlimit(1000000)
def factorial(n):
return 1 if n <= 1 else n * factorial(n-1)
result = factorial(50000) # Will likely crash
The factorial(50000) call exhausts the C stack before Python's limit check can trigger a RecursionError. This results in a hard crash instead of a manageable exception. The next example shows how to prevent this.
import sys
# Reasonable increase
sys.setrecursionlimit(3000)
def factorial(n):
result = 1
for i in range(2, n+1):
result *= i
return result
result = factorial(50000) # Safe iterative approach
The safest solution is to rewrite the recursive logic as an iterative one. The factorial function now uses a for loop instead of calling itself, which completely avoids deep recursion. This allows it to handle large inputs without risking a stack overflow or needing a dangerously high limit. You should always favor this approach for algorithms that require many steps, as it sidesteps the recursion limit entirely and prevents system crashes.
Detecting and debugging infinite recursion with depth tracking
A RecursionError often signals a bug, not just a low limit. Infinite recursion happens when a function never hits its base case and calls itself endlessly. Depth tracking helps you spot this by monitoring how deep the calls go.
The code below demonstrates how easily this can happen when a data structure contains a cycle, causing the traverse_tree function to loop forever.
def traverse_tree(node):
print(f"Node: {node['id']}")
for child in node.get('children', []):
traverse_tree(child)
node = {'id': 1, 'children': []}
node['children'].append(node) # Creates a cycle
traverse_tree(node) # Infinite recursion!
The traverse_tree function doesn't track which nodes it has already visited. When it encounters the cycle where a node is its own child, it gets trapped in an infinite loop. The corrected implementation below shows how to fix this.
def traverse_tree(node, visited=None):
if visited is None:
visited = set()
if id(node) in visited:
return
visited.add(id(node))
print(f"Node: {node['id']}")
for child in node.get('children', []):
traverse_tree(child, visited)
To fix the infinite loop, the corrected traverse_tree function uses a visited set to remember every node it processes. Before traversing a node, it checks if its unique ID is already in the visited set. If so, it returns immediately, breaking the cycle. This technique is essential when working with data structures like graphs or object trees where circular references can occur, ensuring your function always terminates.
Real-world applications
With these management techniques, you can tackle real-world challenges like parsing deeply nested data or building complex object trees.
Parsing deeply nested JSON data structures with sys.setrecursionlimit()
A recursive function is often the most intuitive way to process deeply nested JSON, and temporarily increasing the limit with sys.setrecursionlimit() allows you to handle complex structures without triggering a RecursionError.
import sys
import json
sys.setrecursionlimit(3000) # Increase limit for deeply nested JSON
def parse_nested_json(data, depth=0):
if isinstance(data, dict):
return {k: parse_nested_json(v, depth+1) for k, v in data.items()}
elif isinstance(data, list):
return [parse_nested_json(item, depth+1) for item in data]
return data
nested_json = {"a": {"b": {"c": {"d": {"e": "value"}}}}}
result = parse_nested_json(nested_json)
print(f"Successfully parsed JSON with depth {len(str(nested_json))} characters")
This example shows how to process data with many nested layers. The parse_nested_json function works by calling itself to dig deeper into the structure.
- If it finds a dictionary, it recursively processes each value.
- If it encounters a list, it does the same for each item.
The function stops when it hits a simple value, like a string. Because deeply nested data can exceed Python's standard call stack capacity, sys.setrecursionlimit(3000) is set beforehand. This ensures the program has enough stack space to traverse the entire structure.
Building large recursive data structures with adjusted limits
Your recursive function can also dynamically call sys.setrecursionlimit() as it runs, letting you build large data structures without needing to set a high, arbitrary limit upfront.
import sys
def create_nested_dict(depth):
if depth <= 0:
return "leaf"
if depth > sys.getrecursionlimit() - 50:
new_limit = depth + 100
sys.setrecursionlimit(new_limit)
print(f"Adjusted recursion limit to {new_limit}")
return {"nested": create_nested_dict(depth - 1)}
deep_dict = create_nested_dict(900)
print(f"Created a dictionary nested to depth 900")
The create_nested_dict function constructs a dictionary by calling itself until the depth reaches zero. It includes a conditional check that compares the current depth to the value from sys.getrecursionlimit().
- This check is designed to trigger when the function is 50 calls away from the limit.
- When triggered, it executes
sys.setrecursionlimit(), setting a new limit based on the currentdepthplus an additional 100 calls. This allows the recursion to proceed further.
Get started with Replit
Turn these techniques into a real tool. Describe what you want to build, like "a web app that parses deeply nested JSON and visualizes it" or "a file system analyzer that maps directory trees without hitting recursion limits."
Replit Agent writes the code, tests for errors, and deploys your app. Start building with Replit.
Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.
Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.



.png)