はじめに
プログラムを書いているときに出てくるエラーって英語だらけで何書いてるのかわからないですよね.
今回はエラー出力で見かける「スタックトレース」について,図を用いて簡単に説明してみたと思います.
スタックトレースについて概要だけでも知っていると,エラーの原因を突き止めやすくなるかもしれません
今回は詳細な読み方についてではなく,スタックトレースとはどんなものなのか概要の説明だけしてみます.
本記事は一部内容について ChatGPT にアドバイスをもらいながら作成しました.
自分自身も最近知ったばかりなのでちょっと間違っているかもしれません.
スタックトレースとは
エラー出力の中に以下のような出力を見たことはないでしょうか.
1 Traceback (most recent call last):
2 File "/app/handler/user_handler.py", line 45, in get
3 user = self.repo.find_by_id(user_id)
4 File "/app/service/user_repo.py", line 87, in find_by_id
5 return rows[0] # ← IndexError
6 IndexError: list index out of range
この1~5までの部分を,スタックトレースと言います.
前提知識
プログラムのを書いていて,ある関数の途中で別の関数を呼び出すことがあると思います.
この時,別の関数の処理が終わった時に,元の関数に戻って来れるように,呼び出し位置を記録しています.
文字情報ばかり見ていても分かりづらいので下の図1を用いながら説明したいと思います.
プログラムの動作としては,
- 図のプログラム部分では最初に 緑ブロック🟩(以降,🟩) のところで 青色ブロック🟦の関数を呼び出しています.
- その次に,青色ブロック🟦 から グレーブロック⬛️の関数を呼び出しています.
スタックの動作としては,
- 最初の 🟩 から 🟦 を呼び出した時に,また 🟩 に戻って来れるように, 🟩の情報をスタックに格納します.(動作①)
- 次に,🟦 から⬛️ を呼び出した時は,⬛️から🟦に戻れるように 🟦 の情報を格納します.(動作②)
そして,グレーブロック⬛️ の処理が終わって,🟦 に戻ってきたら, スタックも以下の図2ように🟦部分の情報を取り出します.(動作③)
エラー出力のスタックトレース
本題のエラー出力におけるスタックトレースについてです.
以下の図3のような状況を考えましょう.
関数A → 関数B → 関数C → 関数D の順に呼び出しが行われています.
二重,三重に呼び出しを重ねたため,スタックにはどんどん前の前の呼び出し元が格納されています.
この状況において,プログラムが途中(関数D中)でエラーが起きたとしましょう.
この時にエラー出力で,スタックの中身を上から順に出力していきます.それが,
1 Traceback (most recent call last):
2 File "/app/handler/user_handler.py", line 45, in get
3 user = self.repo.find_by_id(user_id)
4 File "/app/service/user_repo.py", line 87, in find_by_id
5 return rows[0] # ← IndexError
...
この部分です.
中身としては,上の例で言えば,
1 Traceback (most recent call last):
2 🟩内の特定の行で🟦が呼び出された位置
3 🟦内の特定の行で🟥が呼び出された位置
4 🟥内の特定の行で⬛️が呼び出された位置
のような感じで書かれますです.
エラーの原因探索
以上で紹介した「スタックトレース」を知っていれば,
pythonでは エラー時にスタックトレースの一番最初(呼び出しのきっかけ)部分をまず見てみて,
そこから順に呼び出し先を参照し,エラーまでを辿るとエラーの原因が見つけられるかもしれない.
ということになります.
スタックトレースは「どこで」「どんな流れで」エラーが起きたかを教えてくれる“道しるべ”です.
これを読めるようになると,英語のエラーメッセージも怖くなくなります!
【補足】
-
今回はブロック単位で考えましたが,実際にはスタックには関数呼び出しの情報(スタックフレーム)が積まれており,その中に「どのファイルの何行目から呼び出されたか」という位置情報が記録されています.
-
スタックのターミナルへの出力順序は言語によって異なっていて,pythonであればスタックに積まれた順に下から上へ向かう順序(呼び出し元からエラー箇所へ)で出力を行います.一方Go言語ではスタックの上から下になるような順序で出力される点に注意が必要です.


