Fix Python RecursionError: maximum recursion depth exceeded

intermediate🐍 Python2026-03-18| Python 3.x trên Linux, macOS, Windows

Error Message

RecursionError: maximum recursion depth exceeded
#python#recursion#sys

Nguyên nhân gây ra lỗi

Python giới hạn call stack ở 1000 frame theo mặc định. Khi một hàm tự gọi lại chính nó — trực tiếp hoặc qua chuỗi gọi — và không có gì dừng nó trước ngưỡng đó, bạn sẽ gặp:

RecursionError: maximum recursion depth exceeded

Bốn tình huống gây ra lỗi này hầu như mọi lần:

  • Hàm đệ quy không có base case nào cả
  • Base case tồn tại nhưng không bao giờ được đến do lỗi logic
  • Dữ liệu lồng nhau quá sâu — cây JSON, tài liệu XML, các node AST với hàng trăm tầng
  • Vô tình ghi đè một built-in như __eq__ hay __repr__ khiến nó tự gọi lại chính mình

Đọc traceback

Traceback giúp xác định thủ phạm rất rõ ràng. Hai hoặc ba dòng giống nhau lặp đi lặp lại hàng trăm lần:

File "app.py", line 5, in factorial
  return n * factorial(n - 1)
File "app.py", line 5, in factorial
  return n * factorial(n - 1)
  [Previous line repeated 996 more times]

Dòng lặp lại đó chính là vấn đề. Cách sửa phụ thuộc vào lý do tại sao nó cứ lặp mãi.

Cách sửa 1 — Thêm hoặc sửa base case

Chín trong mười trường hợp, đây mới là vấn đề thực sự. Mọi hàm đệ quy đều cần một điều kiện dừng chuỗi gọi.

Sai:

def factorial(n):
    return n * factorial(n - 1)  # không bao giờ dừng

Đúng:

def factorial(n):
    if n n) xuống O(n).

## Cách sửa 5 — Phát hiện gọi đệ quy vô tình trong __repr__ và __eq__
Dễ bỏ sót: định nghĩa `__repr__` rồi dùng `f"{self}"` bên trong. Chuỗi định dạng đó lại kích hoạt `__repr__` một lần nữa. Vòng lặp vô tận.

SAI — đệ quy vô hạn

class Node: def repr(self): return f"Node({self})" # gọi repr trên chính self!

ĐÚNG — tham chiếu giá trị, không phải self

class Node: def init(self, val): self.val = val def repr(self): return f"Node({self.val})"


Bẫy tương tự cũng tồn tại trong `__eq__` và `__hash__`. Nếu một trong hai vô tình gọi cái kia, bạn sẽ thấy vòng xoáy tương tự.

## Xác nhận bản sửa đã hoạt động
Chạy hàm với các trường hợp biên — không, âm, và kích thước từng gây crash trước đó:

import sys print(sys.getrecursionlimit()) # xác nhận giới hạn hiện tại

result = factorial(999) print(result) # số lớn, không có RecursionError

Nếu bạn đã tăng giới hạn, thử gần ngưỡng mới

sys.setrecursionlimit(3000) result = factorial(2500) print("OK")


Không có ngoại lệ nào trên toàn bộ dải đầu vào nghĩa là bản sửa đã hiệu quả.

## Tóm tắt nhanh

  - **Thiếu base case** → thêm điều kiện kết thúc
  - **Logic đúng nhưng dữ liệu quá sâu** → `sys.setrecursionlimit(N)`
  - **Dữ liệu production/lớn** → viết lại bằng vòng lặp + stack tường minh
  - **Bài toán con lặp lại** → thêm `@lru_cache`
  - **Gọi chính mình vô tình** → kiểm tra `__repr__`, `__eq__`, `__hash__`

Related Error Notes