投稿日:2020年10月19日
wagtailのPageモデルはpathの管理方法が独特で、間違ったforループなどでPageの保存などを行うとPathがOverFlowしてしまうことがあります。この記事ではPathOverFlowの解決方法について自分の例を合わせて解説しています。
今回発生したエラーはWagtailで新しくページを作成しようとした際におきました。
Internal Server Error: /09dy80226/pages/add/blog/blogpage/95/
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.6/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/wagtail/admin/urls/__init__.py", line 102, in wrapper
return view_func(request, *args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/wagtail/admin/decorators.py", line 34, in decorated_view
return view_func(request, *args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/wagtail/admin/views/pages.py", line 233, in create
parent_page.add_child(instance=page)
File "/usr/local/lib/python3.6/site-packages/treebeard/mp_tree.py", line 1013, in add_child
return MP_AddChildHandler(self, **kwargs).process()
File "/usr/local/lib/python3.6/site-packages/treebeard/mp_tree.py", line 387, in process
newobj.path = self.node.get_last_child()._inc_path()
File "/usr/local/lib/python3.6/site-packages/treebeard/mp_tree.py", line 1114, in _inc_path
raise PathOverflow(_("Path Overflow from: '%s'" % (self.path, )))
treebeard.exceptions.PathOverflow: Path Overflow from: '0001000200050004ZZZZ'
バグの内容的にpathがオーバーフロー、つまり許容できる最大値を超えてしまったようです。自分のコードに思い当たるforループがあったため、とりあえずその部分を修正したのですが、
問題は解決せずページを保存しようとするとバグは発生しつづけました。
エラーの原因はStackTraceに表示された通りPathがオーバーフローしていることが原因です。しかし、このオーバーフローは今保存しているページではなく前回保存したページで起きています。
Wagtailでは新しく作成するPageのpathを前回作成したPageのpathをインクリメントして生成するのですが、その値が最大値までいってしまったため、pathの生成に失敗しているのです。StackTraceで指定されたパスは'0001000200050004ZZZZ'で最後のZZZZがオーバーフローしていることがわかります。
ページを何十万も作成してこのエラーが出た場合には、もう新しくDBを作るしかありませんが、今回は単純に自分のforループのミスなのでなんとか解決できそうです。
解決方法としては以下の流れになります。
今回はDjangoのshellから解決します。
python manage.py shell
Python 3.6.9 (default, Aug 14 2019, 13:02:21)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from blog.models import BlogPage
>>> page = BlogPage.objects.get(path="0001000200050004ZZZZ")
>>> blog_pages = BlogPage.objects.all().order_by("-created")
>>> blog_pages[0].path
'0001000200050004ZZZZ'
>>> blog_pages[1].path
'0001000200050004000A'
>>> page.path="0001000200050004000B"
>>> page.save()
簡単に解説します。
まずはpage = BlogPage.objects.get(path="0001000200050004ZZZZ")で問題のあるPageインスタンスを取得します。ここでpathとして指定している値はエラーで指定された値です。
次にBlogPage.objects.all().order_by("-created")で作成日時順に並べたページを取得しています。自分はPageの作成日時をDateTimeFieldのcreatedという名前のfieldで設定していますが、このfieldがない場合には-idで並べても良いでしょう。
blog_pages[0].pathで直前に作成したページに問題があることが確認できました。
ということで問題が起きたページのさらに一つ前のページのpathを、blog_pages[1].pathで確認しています。パスがオーバーフローしたことを考えるとpathは36進数のようです。そのため、0001000200050004000Aの次の値、0001000200050004000Bをpathとして設定し保存しました。
これで解決です。