エラーメッセージの読み方: スタックトレースのどこから読むと原因に最短で着くか
赤いログを上から全部読むのは遠回り。スタックトレースのどこから読むか、undefined・型・非同期・importの型分類、エラーをClaude Codeに渡して原因を絞るコツを実例で。
赤い文字が画面に40行流れてきたとき、僕は長いこと「上から全部読む」をやっていました。
結果どうなったか。3行目あたりで node_modules の中の見知らぬファイル名にぶつかって、「あ、ライブラリのバグかも」と勘違いする。そこから1時間、自分のコードじゃない場所を疑って溶かす。実際の原因は、自分が書いた42行目の1か所だったのに。
エラーメッセージは、上から読むものでも、最後の行だけ見るものでもありません。読む順番が決まっているんです。順番さえ知っていれば、40行のログでも原因にたどり着くのは1〜2分。今日はその読み方を、僕の勘違い込みで具体的に書きます。
デバッグの手順全体(症状から仮説を絞る、git bisectで挟み撃ち、ログ戦略)は姉妹記事の Claude Codeでバグを潰す手順 にまとめました。この記事は、その入口にあたる「エラー文1枚から原因の場所を当てる読解」だけに集中します。
この記事の要点
- スタックトレースは**「自分のコードの最初の行」**から読む。
node_modulesやフレームワーク内部の行はいったん飛ばす。 - エラーは型で分類すると速い。undefined/null・型・非同期・import の4つを覚えれば、初動の8割は片付く。
- エラー文をClaude Codeに渡すときは、最初の失敗行・自分のコードの該当行・直前の操作の3点をセットにする。これだけで回答が一般論から具体策に変わる。
- 原因を確かめる最後の砦は最小再現。10行に削っても同じエラーが出るなら、その10行の中に原因がある。
- 「エラーメッセージ」と「原因」は別物。文末のメッセージは症状で、トレースの上のほうに原因がいることが多い。
まず分解する:エラーは3つの部品でできている
長いエラーも、構造は毎回同じです。3つの部品に分けて見ます。
| 部品 | 何が書いてあるか | 読むときの役割 |
|---|---|---|
| エラーの種類 | TypeError、SyntaxError、ReferenceError など | どの系統の問題か当たりをつける |
| メッセージ本文 | Cannot read properties of undefined (reading 'map') | 何が起きたかの一文。症状であって原因ではない |
| スタックトレース | at ProductList (src/ProductList.tsx:42:18) の連なり | どこで起きたか。原因の住所 |
ありがちな間違いは、真ん中の「メッセージ本文」だけを読んで満足することです。Cannot read properties of undefined は「何かが undefined だった」としか言っていません。どの変数が、なぜ undefined になったかは、トレースを読まないと分かりません。
逆に、種類とトレースを先に見ると、メッセージ本文の意味がすっと入ってきます。順番が大事、というのはこういうことです。
スタックトレースは「自分のコードの最初の行」から読む
ここが今日いちばん伝えたいところです。
スタックトレースは、エラーに到達するまでに呼ばれた関数が、新しい順(つまり一番奥で起きたものが上)に並んだリストです。多くの人は一番上から読みますが、一番上はたいてい node_modules の中や React 内部のコードです。そこはあなたが直す場所ではありません。
読むべきは、**上から眺めていって最初に出てくる「自分のプロジェクトのファイル」**です。例を見てください。
TypeError: Cannot read properties of undefined (reading 'map')
at Array.map (<anonymous>)
at renderList (node_modules/react-dom/cjs/react-dom.development.js:9281:18)
at ProductList (src/components/ProductList.tsx:42:18) ← ここから読む
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:15486:18)
上の2行(<anonymous> と react-dom)は通り道です。原因の住所は3行目、src/components/ProductList.tsx の42行目。ここを開けば、undefined.map() を呼んでいる箇所が必ずあります。
僕がやっていた「上から全部読む」は、通り道の標識を一つずつ確認しながら歩くようなもので、目的地(自分のファイル)に着くのが遅れるだけでした。node_modules という文字が見えたら、その行は飛ばす。これを徹底するだけで、初動が劇的に速くなります。
VS Code でターミナルのファイルパスは Ctrl を押しながらクリックすると、その行に直接飛べます。トレースを読みながら該当行へジャンプするのが、いちばん手戻りが少ないです。
エラーの型を4つに分類する
ファイルと行が分かったら、次は「どの種類の故障か」を当てます。実務で出るエラーの大半は、次の4つの型に収まります。型が分かると、見るべき場所と直し方の方向が一気に絞れます。
| 型 | 代表的なメッセージ | 真っ先に疑う場所 |
|---|---|---|
| undefined/null | Cannot read properties of undefined、null is not an object | データの形(配列のはずがnull)、初期値、描画タイミング |
| 型 | Type 'string' is not assignable to type 'number'、TS2345 | 型定義とのズレ、APIレスポンスの型、any の混入 |
| 非同期 | Promise rejection、値が undefined のまま進む | await の付け忘れ、.then の戻り忘れ、競合 |
| import/モジュール | ERR_MODULE_NOT_FOUND、Cannot find module、SyntaxError: Cannot use import | パスの綴り、拡張子、type: module 設定、循環参照 |
undefined/null 型
いちばん出会う型です。Cannot read properties of undefined (reading 'map') の 'map' の部分が、ヒントになります。map を呼べるのは配列だけ。つまり「配列が来るはずの場所に undefined が来た」と読めます。
疑う順番は、(1) そのデータはどこから来るか(APIなら本当に配列を返しているか)、(2) 初期値は何か(useState() で空配列を入れ忘れていないか)、(3) データが届く前に描画していないか、の3つ。だいたいこのどれかです。
型エラー
TypeScript で TS2345 のような番号付きエラーが出たら、番号より最初の1個に注目します。20個出ても、1個目がAPI型の変更で、残り19個はその連鎖、というのが本当によくあります。1個目を直して再実行すると、まとめて消えることが多いです。
非同期エラー
undefined なのにトレースが浅い、ログの順番が直感と合わない、エラーが出たり出なかったりする——このあたりは非同期を疑います。const data = fetchUser() のように await を忘れると、data は Promise のままで、data.name が undefined になります。「動いたり動かなかったり」は、ほぼ非同期の競合だと思って間違いないです。
import/モジュールエラー
ERR_MODULE_NOT_FOUND や Cannot find module は、起動すらできない型です。コードのロジックは正しくても、ファイルが見つからない。綴り、拡張子(ESMだと .js まで書く必要がある)、package.json の type 設定、相対パスの ./ 抜けを順に見ます。
コピペで動く:エラーを型に粗分けする道具
長いログを Claude Code に渡す前に、まず型を粗く判定すると初動が速くなります。次のファイルはそのまま実行できます。標準入力からの貼り付けにも、ファイル指定にも対応しています。
// classify-error.mjs
// 使い方:
// node classify-error.mjs error.log ← ファイルを読む
// echo "...エラー..." | node classify-error.mjs ← 貼り付けを読む
import fs from "node:fs";
// 入力を取得(引数のファイル優先、なければ標準入力)
function readInput() {
const file = process.argv[2];
if (file) return fs.readFileSync(file, "utf8");
return fs.readFileSync(0, "utf8"); // 0 = stdin
}
const text = readInput();
// エラーの型を判定するルール(上から順にマッチ)
const rules = [
[/Cannot find module|ERR_MODULE_NOT_FOUND|Cannot use import/i, "import/モジュール(パス・拡張子・type設定を確認)"],
[/Cannot read properties of (undefined|null)|is not an object/i, "undefined/null(データの形・初期値・描画タイミング)"],
[/TS\d{4}|is not assignable to type/i, "型(型定義とのズレ・APIレスポンス型・anyの混入)"],
[/UnhandledPromiseRejection|await is only valid|Promise/i, "非同期(awaitの付け忘れ・戻り忘れ・競合)"],
];
// 自分のコードの最初の行を拾う(node_modules を除外)
function firstOwnFrame(log) {
const lines = log.split("\n");
for (const line of lines) {
const m = line.match(/\(?((?:src|app|lib|pages)\/[^):]+:\d+:\d+)/);
if (m && !line.includes("node_modules")) return m[1];
}
return null;
}
const hits = rules.filter(([re]) => re.test(text)).map(([, label]) => label);
const frame = firstOwnFrame(text);
console.log("推定タイプ:", hits.length ? hits.join(" / ") : "不明(最初の失敗行を手で確認)");
console.log("最初の自分の行:", frame ?? "見つからず(パスのパターンを調整)");
node classify-error.mjs error.log
これは完璧な診断器ではありません。狙いは、Claude Code に渡す前に「import なのか、データの形なのか、型なのか、非同期なのか」を粗く分けて、最初の自分の行 を自動で拾い出すことです。この2つが分かっているだけで、次の一手の精度が変わります。
エラーをClaude Codeに渡して原因を絞る
型と該当行が見えたら、Claude Code の出番です。ただし、赤いログを丸ごと貼って「直して」だと、返ってくるのは「環境変数を確認してください」のような一般論になりがちです。これは Claude Code が悪いのではなく、エラー文の外にある情報を渡していないからです。
僕がいま使っているのは、次の3点セットを必ず添えるやり方です。
- 最初の失敗行(メッセージ本文の一行)
- 自分のコードの該当行(トレースから拾った
src/...:42) - 直前にやった操作(何を変えた直後に出たか)
この形でプロンプトにします。コピペで使えます。
claude -p "
このエラーの原因を1つに絞ってください。
# 最初の失敗行
TypeError: Cannot read properties of undefined (reading 'map')
# 自分のコードの該当行
src/components/ProductList.tsx:42
# 直前の操作
APIのレスポンス形式を配列から { items: [...] } に変えた
制約:
- まず該当行とその関数だけを読む
- 原因の仮説は最大3つまで。可能性の高い順に並べる
- 関係ないリファクタリングは提案しない
- 最後に、原因を確かめる最小再現コードを書く
"
「仮説は最大3つ」が効きます。10個並べられても結局どれも検証されません。上の例なら「(1) レスポンスの形が変わり data.map が data.items.map になっていない、(2) 受け取り側の型が古い、(3) ローディング中に描画している」の3つで十分に当たります。
エラーの「渡し方」をもっと深掘りした実例は Claude Codeにエラーを「直して」と言う前に にまとめました。プロンプトのテンプレートが欲しい人はそちらへ。
原因を確かめる:再現を最小化する
仮説が出たら、信じる前に確かめます。確かめる一番確実な方法が、最小再現です。
巨大な画面のまま直すと、たまたま別の状態で通っただけなのか、本当に原因を消したのか分かりません。エラーが出ているロジックだけを、外部依存を切って数行に切り出す。それでも同じエラーが出れば、原因はその数行の中に確定します。
たとえば冒頭の undefined.map なら、UIもAPIも全部はがして、こう書きます。
// repro.mjs(最小再現:これを実行して同じエラーが出るか確かめる)
function names(users) {
return users.map((u) => u.name); // ← 42行目で起きていたのと同じ操作
}
// APIが配列でなく undefined を返したケースを再現
console.log(names(undefined));
node repro.mjs
これを実行すると、UIもReactも無関係に、同じ Cannot read properties of undefined が出ます。つまり原因は「names に配列以外が渡ること」で確定。あとは入口でガードするだけです。
// 修正版:配列でなければ空配列に正規化する
function names(users) {
if (!Array.isArray(users)) return [];
return users.map((u) => u.name ?? "(no name)");
}
最小再現があると、修正後に「直った」と言える根拠もできます。同じ repro.mjs がエラーを出さなくなったら、それが証拠です。
公式リファレンスで「メッセージの意味」を裏取りする
メッセージの意味が分からないときは、推測で進めず公式で引きます。これが結局いちばん速いです。
JavaScript の標準エラー名(TypeError や ReferenceError が何を意味するか)は MDN の JavaScript error reference に網羅されています。Node.js のエラーは Node.js Errors のドキュメント が一次情報で、ここには「error.message は将来変わる可能性があるので、条件分岐には error.code を使うほうが安定する」という大事な指針も書かれています。エラー文の文字列で if を書いている人は、ここを一度読むと事故が減ります。
よくある質問
Q. スタックトレースが長すぎて、どこが自分のコードか分かりません。
上から眺めて、node_modules を含まない最初の行を探してください。プロジェクトの src/ や app/ で始まるパスが目印です。本記事の classify-error.mjs を使うと、その行を自動で拾えます。
Q. メッセージ本文だけ読んでも直せないのはなぜ?
メッセージは「症状」だからです。undefined だった とは言っていても、なぜ undefined になったか は書いていません。原因はトレースが指す該当行の、さらに「そのデータがどこから来たか」をたどった先にあります。
Q. エラーが出たり出なかったりします。何を疑えばいい?
ほぼ非同期の競合です。await の付け忘れ、Promise の戻し忘れ、データ取得前の描画を順に確認してください。再現性が低いバグの挟み撃ちは Claude Codeでバグを潰す手順 のgit bisectが向いています。
Q. Claude Codeにログを丸ごと貼ってもいい? 貼っても動きますが、一般論が返りやすいです。最初の失敗行・自分のコードの該当行・直前の操作の3点を添えると、回答が具体的になります。社外秘の値やトークンがログに混ざっていないかだけ確認してから貼ってください。
Q. 型エラーが20個出ました。全部直すべき?
まず1個目だけ直して再実行してください。多くは1個目が根本原因で、残りは連鎖です。1個直すと一気に減ることがよくあります。全部に型アサーション(as)を足すのは、原因を隠すだけなので避けます。
まとめ
エラーメッセージは、感情的に身構えるものではなく、読む順番が決まった文書です。種類を見て、トレースから自分のコードの最初の行を拾い、4つの型のどれかに当てはめる。ここまでで原因の場所はほぼ絞れます。
そのうえで Claude Code には「最初の失敗行・該当行・直前の操作」をセットで渡し、仮説は3つまでに制限する。最後に最小再現で確かめてから直す。この読解の型を一度しみこませると、40行の赤いログを見ても、もう身構えなくなります。
僕自身、node_modules の行を飛ばして自分のファイルから読む、と決めただけで、原因にたどり着く時間が体感で半分以下になりました。手を動かす前に、まず正しい場所を読む。遠回りに見えて、これがいちばん速い直し方でした。
エラー診断をチームで属人化させたくない場合は、バグ報告フォームや再現の保存ルールまで整えるのが近道です。実務向けの型は Claude Code教材・テンプレート と 導入相談・研修 にまとめています。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeに1ファイルだけ直させる指示文のつくり方
「もっと良くして」で40行も変えられた失敗から学んだ、触る範囲・検証・戻し方をセットにしたClaude Code用の依頼文テンプレートを紹介します。
Claude Code の権限拒否から復旧する: 止まった理由を次の安全手順に変える
Claude Code のコマンドが拒否されたとき、焦って許可を広げずに、拒否理由、代替手順、証拠コマンド、再試行条件へ分解する方法。
Claude Codeにビルド→スモークテスト→自動修正を回させる足場の作り方
最小スモークテストの選び方、失敗ログを食わせて直させるループ、回数上限と確認ゲートで暴走を止める方法を、コピペで動くコード付きで紹介します。