RecursionError: maximum recursion depth exceeded は、関数が自分自身を呼ぶ「再帰」が、Python の上限(既定で 1000 段)を超えたときのエラーです。 原因は2つに分かれます。

原因 見分け方 直し方
終わらない再帰(終了の条件の間違い、意図しない再帰) どんなに小さいデータでも出る 終了の条件・書き間違いを直す
データが深すぎる(階層の深い木・長いリスト) データが大きいときだけ出る ループに書き換える(上限を上げるのは最後の手段)

確認環境:Python 3.10・3.11・3.12・3.13・3.14(Linux、スタックサイズ 8MB)(確認日 2026年10月11日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「RecursionErrorの原因と直し方|Pythonの再帰」

上限の 1000 段で、実際に届く深さ

import sys
sys.getrecursionlimit()       # 1000

def f(n):
    try:
        return f(n + 1)
    except RecursionError:
        return n
f(0)
Python 届いた深さ エラー文
3.10 996 maximum recursion depth exceeded while getting the str of an object
3.11 997 同上
3.12・3.13・3.14 998 maximum recursion depth exceeded

1000 段より少し手前で止まりました(呼び出し元の分も数えられるため)。エラー文の後ろの while ... は、版や、どの処理の途中だったかで変わります。

意図しない再帰:@property・getattr・repr

再帰を書いたつもりが無いのに出るときは、次の書き間違いを疑います。確認環境では、どれも maximum recursion depth exceeded になりました。

class User:
    @property
    def name(self):
        return self.name          # ← 自分自身(property)を呼んでいる
書き間違い 直し方
@property の中で、同じ名前の属性を返す 値は別の名前(self._name)に入れる
__getattr__ の中で self.data などを使い、data が無い self.__dict__ から取る、または object.__getattribute__
__repr__ の中で {self!r}・repr(self) 中身の項目だけを表示する
setter の中で self.name = value self._name = value
class User:
    def __init__(self, name):
        self._name = name
    @property
    def name(self):
        return self._name         # 別の名前から返す

トレースバックに同じ行が何度も出て、[Previous line repeated 996 more times] のように表示されたら、その行が自分を呼んでいます。

データが深すぎる:ループに書き換える

# 再帰:木の深さが 1000 を超えると RecursionError
def depth(node):
    return 1 + max((depth(c) for c in node['children']), default=0)

# ループ:自分でスタック(やることのリスト)を持つ
def depth_loop(root):
    best, stack = 0, [(root, 1)]
    while stack:
        node, d = stack.pop()
        best = max(best, d)
        stack.extend((c, d + 1) for c in node['children'])
    return best

深さ 5,000 の木で、再帰の版は RecursionError、ループの版は 5000 を返しました。 組織図・カテゴリの階層・フォルダーの中身など、深さがデータ次第の処理は、最初からループで書いておくと安全です。

フィボナッチ数など、メモ化(lru_cache)では足りない

from functools import lru_cache
@lru_cache(None)
def fib(n): return n if n < 2 else fib(n - 1) + fib(n - 2)
fib(5000)          # RecursionError(計算の回数は減っても、呼び出しの深さは 5000 のまま)

lru_cache は同じ計算の繰り返しを減らしますが、最初の呼び出しの深さは変わりませんでした。 ループで書くと、深さの問題は起きません。

def fib_loop(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a          # fib_loop(5000) は lru_cache 版と同じ値

setrecursionlimit で上限を上げると、版によってはクラッシュする

import sys
sys.setrecursionlimit(1_000_000)
def g(n): return 0 if n == 0 else 1 + g(n - 1)
g(200_000)
Python 結果(確認環境)
3.10 Segmentation fault(終了コード 139)。エラーのメッセージも出ずに止まった
3.11〜3.14 200000(90万段でも動いた)

Python の関数どうしの再帰は、3.11 以降は深くしても落ちませんでしたが、3.10 では Python ごと異常終了しました。 公式ドキュメントでも、上限を高くしすぎるとクラッシュすることがあると注意されています。

組み込みの処理(json など)の深い再帰

sys.setrecursionlimit(1_000_000)
json.dumps(深さ 30万 のリスト)
Python 結果(確認環境)
3.10・3.11 Segmentation fault(終了コード 139)
3.12・3.13 RecursionError: maximum recursion depth exceeded while encoding a JSON object
3.14 RecursionError: Stack overflow (used 8128 kB) while encoding a JSON object

3.12 以降は、組み込みの処理は Python の上限とは別の仕組みで守られるようになりました(3.12 の変更点)。3.14 では、エラー文に Stack overflow (used ... kB) と使ったスタックの量が表示されました。上限を上げるのは、ループに書き換えられないときの最後の手段にし、上げるなら本番と同じ版で、最大の深さのデータで試しておきます。

JSON・コピーの深いデータ

処理 深さ 5,000 のリスト(既定の上限)での結果
json.dumps 3.10 は RecursionError、3.12・3.14 は動いた
json.loads(深さ 10 万の文字列) RecursionError(3.14 は Stack overflow (used 8136 kB))
copy.deepcopy RecursionError

外部から受け取った JSON が異常に深いと、読み込みで RecursionError になります。 受け取るデータの深さに上限を決めておくか、エラーを受け取って「不正なデータ」として扱います。

確認の手順(チェックリスト)

順番 確認すること 方法
1 小さいデータでも出るか 出るなら終わらない再帰(書き間違い)
2 繰り返している行 トレースバックの Previous line repeated
3 property・__getattr__・__repr__ 自分と同じ名前を参照していないか
4 データが深いだけ ループ(自分でスタックを持つ)に書き換え
5 上限を上げるなら 3.10 以前はクラッシュに注意。本番の版で試す
6 外部の JSON 深さに上限を決める

よくある質問

Q. Java の StackOverflowError や、JavaScript の Maximum call stack size exceeded と同じですか。 A. 同じく「再帰が深すぎる」エラーです。Java は関連記事の「Java StackOverflowErrorの原因と対処|再帰と-Xss早見表」、JavaScript は「Maximum call stack size exceededの原因と直し方|再帰とループ」で扱っています。

まとめ

  • 再帰が上限(既定 1000 段)を超えたエラー。実際には 996〜998 段で止まった
  • 小さいデータでも出るなら、終わらない再帰。@property などの書き間違いを疑う
  • データが深いなら、ループに書き換える。lru_cache では深さは変わらない
  • setrecursionlimit を上げると、3.10 は Segmentation fault で落ちた
  • 3.12 以降、組み込みの処理は別の仕組みで守られる。3.14 は Stack overflow (used ... kB) と表示

参考・出典

確認日はいずれも 2026年10月11日です。

  • Python ドキュメント「sys — System-specific parameters and functions」(setrecursionlimit):https://docs.python.org/3/library/sys.html#sys.setrecursionlimit
  • Python ドキュメント「What's New In Python 3.12」:https://docs.python.org/3/whatsnew/3.12.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「RecursionErrorの原因と直し方|Pythonの再帰」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?