
スタックトレースの読み方|どこで落ちたかを最短で特定する手順
「なんかエラーで落ちてます」と言われてログを開いたら、見慣れない英語の行が画面いっぱいに、何十行も並んでいる。at ...、File "..."、Caused by ...——どれも似たような行に見えて、どこから読めばいいのか分からない。とりあえず一番上をコピーして検索してみるけれど、いまいちピンとこない。そうこうしているうちに、「まだ直らない?」の催促だけが増えていく——。
そんな経験、ありませんか。
スタックトレース(例外が発生するまでの、プログラムの呼び出しの足あと)は、長いだけで身構えてしまいますが、全部を読む必要はありません。大事なのは、その長い行の中から「本当に見るべき数行」を拾い出して、どこで・なぜ落ちたのかにたどり着くこと。この記事では、スタックトレースを最短で読み解くための順番を、言語ごとの「発生箇所は上か下か」の違いも含めて、一人運用の目線で整理します。まずは「どこに自分たちのコードがあるか」を探すところから、一緒に見ていきましょう。
結論:長いスタックトレースは、①例外の種類とメッセージ(一番大事な「何が起きたか」の一文)を読む ②自分たちのコードの行を探す(フレームワークやライブラリの行は飛ばし、自社のファイルパスが出てくる一番深いところを見る)③Caused by などの「本当の原因」をたどる(表に出た例外の裏に、根っこの例外が隠れていることが多い)④再現条件につなげる(どの入力・どのタイミングでそこを通るかを考える)——の順で進めます。まずは①の「何が起きたか」の一文を見つけるところから。
言語やフレームワーク、ログの設定によって、行の並び方や表記は変わります。ここで示すのは「どんな言語でも通用する読み方の軸」です。実際の対処は、本番へ反映する前に検証環境と公式情報で確認してください。
そもそもスタックトレースは何を表しているか

読み方の前に、スタックトレースが何を写したものかだけ、押さえておきます。ここが分かると、長い行の意味が急に整理されます。
プログラムは、ある関数(処理のまとまり)が別の関数を呼び、それがまた別の関数を呼ぶ……という入れ子で動いています。エラーが起きた瞬間、その「今どこを通ってきたか」の足あと——呼び出しの積み重なり(スタック)を一覧にしたものが、スタックトレースです。
つまり、at ... や File "..." の一行一行は、「この関数が、この行で、次の関数を呼んだ」という通り道の記録です。ずらっと並んでいるのは、エラーが深いところで起きたぶん、そこにたどり着くまでの道のりが長かった、というだけのこと。だから、全部を読む必要はなく、「自分たちのコードが通った場所」と「本当に落ちた一点」だけを拾えばいいわけです。
スタックトレースの「スタック」=関数の呼び出しが積み重なった状態のこと。エレベーターで例えると、1階から乗って各階に寄りながら上がっていった履歴のようなもの。エラーは、いちばん奥まで進んだ先で起きています。
まず「例外の種類とメッセージ」を読む
長いトレースの中で、いちばん情報量が多い一行があります。例外(エラー)の種類と、その説明メッセージです。ここを最初に読むと、「そもそも何が起きたのか」の当たりが一気につきます。
多くの言語で、この一行はだいたいこんな形をしています。
例外の種類: 具体的な説明メッセージ
例(言語ごとに表記は違いますが、考え方は同じ):
NullPointerException: Cannot invoke "User.getName()" because "user" is null
TypeError: 'NoneType' object is not subscriptable
Error: connect ECONNREFUSED 127.0.0.1:5432
PDOException: SQLSTATE[HY000] [2002] Connection refused
ここで読み取りたいのは、次の2つです。
- 例外の「種類」:
NullPointerException(空の値を使おうとした)、TypeError(型が合わない)、Timeout/Connection refused(相手につながらない)など。種類だけで、どのジャンルの問題か(値の不整合なのか、外部接続なのか、権限なのか)がかなり絞れます。 - 後半の「説明メッセージ」:ここが具体的なほど助かります。
because "user" is nullなら「userが空だった」、ECONNREFUSED 127.0.0.1:5432なら「そのアドレス・ポート(5432=よくあるDBのポート)につなごうとして拒否された」と、落ちた理由の核心が書かれていることが多いです。
この一文を読むだけで、「あ、DBにつながっていないのかも」「どこかで値が空のまま使われたな」と、調べる方向が定まります。まずここ、と決めておくだけで、長いトレースへの身構えは、ずいぶん軽くなります。
発生箇所は「上」か「下」か——自分たちのコードを探す

例外の種類が分かったら、次は「どこで落ちたか」です。ここで一つ、つまずきやすいポイントがあります。「実際に落ちた場所」が、トレースの上にあるか下にあるかは、言語によって逆なのです。
- Python:先頭に
Traceback (most recent call last):と出て、いちばん下の行が「実際に例外が起きた場所」です(most recent call last=最後の呼び出しが最後、の意味)。上から下へ、呼び出した順に並びます。 - Java:いちばん上の行(
Exception in thread ...の直後の最初のat)が、例外がスローされた最も奥の場所です。下に行くほど、それを呼び出した側(外側)になります。 - JavaScript(Node.js)/PHP など:多くは上のほうが発生箇所寄りです(環境で表記の差はあります)。
言語ごとの向きを毎回覚えていなくても大丈夫な、どの言語でも効く探し方があります。それは、「自分たちのコードのファイルパスが出てくる行」を探すこと。
トレースの大半は、フレームワークやライブラリ(vendor/、site-packages/、node_modules/、org.springframework... など)の中を通った記録で、そこは基本的に「通り道」にすぎません。あなたが直せるのは、自社のソースが置かれた場所(app/、src/、自社ドメインのパッケージ名など)です。だから、
- まず自社のファイルパスが出てくる行にだけ目印をつける
- その中で、いちばん深い(例外の発生に近い側の)行を、最初の容疑者とする
とすれば、上か下かで迷っても、見るべき数行に自力でたどり着けます。「ライブラリの奥で落ちているように見えても、そこへ渡した値や呼び出し方に原因があることが多い」——だから、自分たちのコードが最後に関わった行が、いちばん調べ甲斐のある場所になります。
「一番目立つ例外」が真犯人とは限らない——Caused by を追う
ここが、スタックトレースでいちばん引っかかりやすいところです。表に出ている例外の裏に、本当の原因になった別の例外が隠れていることがよくあります。
Java でいう Caused by: がその代表です。一つのトレースの中に、
...(表向きの例外)...
Caused by: ...(本当の原因の例外)...
Caused by: ...(さらにその原因)...
と、Caused by が続けて出ることがあります。これは、「Aという処理が失敗した。なぜなら、その内側でBが失敗したから。さらにBは、Cが失敗したから」という原因のつながりを表しています。
このとき見たいのは、いちばん最後(根っこ)の Caused by です。表向きの例外(たとえば「データの取得に失敗しました」)だけを見て検索しても解決しないのは、根っこ(たとえば「DBに接続できなかった」)を見落としているから、というのはよくあるパターンです。
Caused by という言葉が出ない言語でも、考え方は同じです。
- Python:
The above exception was the direct cause of the following exception:(上の例外が、下の例外の直接の原因)やDuring handling of the above exception, another exception occurred:(上の例外の処理中に、別の例外が起きた)という一文で、例外が連鎖していることが示されます。 - どの言語でも、「本当の入口はどこか」を、連鎖の根っこまで下りて確かめるのが基本です。
一番上(または一番目立つ場所)の例外は、あくまで最終的に表に出た結果。真犯人は、その奥にいることがある——そう思って一段深く見るだけで、見当違いの調査を減らせます。
影響:読む順番が決まっていると、何が変わるか
- 「長い英語のログ」が「何が・どこで・なぜ落ちたか」に変わり、次に何を調べればいいかがはっきりする
- 例外の種類とメッセージを先に読む癖がつくと、見当違いのキーワードで検索し続ける遠回りを避けられる
Caused by(根っこの原因)を追えるようになると、表向きのエラーだけ直して再発するという空振りが減る- 「自社コードの行を探す」を型にしておけば、自分が不在のときも、誰かが同じ順番で当たりをつけられる
放置して毎回その場の勘で読んでいると、同じ種類のエラーでも、対応時間も結論もバラバラになりがちです。逆に言えば、「まず種類とメッセージ、次に自社の行、最後に根っこの原因」と順番を一度決めておけば、初めて見るトレースでも、落ち着いて糸口を手繰れます。
明日やること:手元のエラーで「読む順番」を1回なぞる
- 直近で出た本物のエラーログ(テスト環境や過去の障害記録でよい)を一つ開き、例外の種類と説明メッセージの一行がどれかを、指でなぞって特定してみる。
- その同じトレースで、自社のファイルパスが出ている行にだけ印をつけ、その中の「いちばん深い行」を見つけてみる。使っている言語で発生箇所が上か下かも、あわせて確認しておく。
Caused byや「上の例外が原因」といった連鎖の表示があるかを探し、あれば根っこ(最後の原因)まで下りて読む。- 余力があれば、よく落ちるポイントについて、「この例外が出たら、まずこの行を見る」という一言メモを、運用ドキュメントや対応履歴に一行だけ残しておく。
ここまでで15〜20分ほど。一度この順番で読み通しておくと、次に本番でトレースが出たとき、画面いっぱいの行に飲まれずに、見るべき数行へ手が伸びるようになります。
スタックトレース読み解きチェックリスト
最低ライン(優先順位つき:これだけで当たりがつく) 1) 種類とメッセージを読む:例外の「種類」と、後半の「説明メッセージ」から、何が起きたかの当たりをつける 2) 自社コードの行を探す:ライブラリ・フレームワークの行は飛ばし、自社のファイルパスが出る「一番深い行」を最初の容疑者にする 3) 根っこの原因を追う:Caused by や「上の例外が原因」があれば、連鎖の一番最後まで下りて本当の原因を見る
余力が出たら拡張
- 使っている言語で「発生箇所は上か下か」を一度確認し、チームで共有しておく
- よく出るエラーは「この例外→まずこの行・この設定を見る」の対応メモを残す
- 再現条件(どの入力・どのタイミングで通るか)まで書き添えて、調査ログとして資産化する
免除条件(省略可)
- 使い捨ての検証環境で、業務に影響しない一時的なエラーは、根っこの追跡まで踏み込まなくてよい。ただし「種類とメッセージ」だけは控えておくと後で役立つ。
確認項目
- まず例外の「種類」と「説明メッセージ」の一行を探して読んでいる
- 説明メッセージの後半(
because .../接続先・ポートなど)から核心を読み取れる - トレースの大半はライブラリの通り道だと分かっており、飛ばして読める
- 自社のファイルパスが出てくる「一番深い行」を最初の容疑者にできる
- 使っている言語で、発生箇所が「上」か「下」かを把握している
-
Caused by/「上の例外が原因」の連鎖を、根っこまでたどれる - 表向きの例外だけでなく、本当の原因(根っこ)を見て対処している
- よく出るエラーは「まずこの行を見る」の一言メモを残している
よければ、こちらも
スタックトレースを読めることは、「どこで落ちたか」を最短で突き止める力です。その先の「なぜ落ちたか(再現・原因特定)」や、後から追えるようにログを仕込む工夫、エラーメッセージそのものの読み解きも、あわせて型にしておくと、調査がぐっと楽になります。
- バグ報告から再現・原因特定までの最短ルート|調査の順番
- 再現しないバグの調査の進め方|環境・タイミング依存を疑う
- 大量ログからエラーを絞り込む|grep・tail・lessの実務術
- 問い合わせ対応を「調査ログ」として残して資産にする方法

長いスタックトレースは、最初はどこから読めばいいのか分からず、それだけで気持ちが重くなるものです。でも、「種類とメッセージを読む」「自社の行を探す」「根っこの原因を追う」と順番を決めておくだけで、あの画面いっぱいの行も、ずいぶん怖くなくなります。 今日は、手元にあるエラーログを一つ開いて、例外の種類の一行を探してみるだけで十分です。全部を読まなくていい、と分かった時点で、もう調査は前に進んでいます。
ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。