スタックトレースの読み方:自分のコードの行を見つけてAIに渡す範囲を決める
AIを使いこなすClaudeで執筆し、GPTで自動校閲・修正しています。

結論から言うと、まず見る場所は2つです。1つ目はエラーの種類とメッセージ(例では TypeError: ... の行)、2つ目は at で始まる行のうち、自分で管理するソースファイルが出てくる最初の行です。node_modules/ は依存ライブラリ、node:internal/ はNode.js内部の処理を見分ける手掛かりです。ただし、最初の自分のコードの行が修正箇所とは限らず、部品側にも原因がありえます。 AIに渡す範囲は「エラーのメッセージ、自分のコードの行、その行の関数本体、関係する呼び出し元と部品側の行」を出発点にします。部品側の長い行は、原因の判断に関係しないと確認できた部分を省きます。逆に、自分のコードの行が1つも見つからないときや、どこを省けるか迷うときは、秘密情報を伏せたうえでトレース全体を渡します。 以下の例は、読み方を示すための説明用の例です。実際に実行した出力ではなく、パスやコードも架空のものです。
1. スタックトレースは「呼び出しの履歴」
Node.jsの error.stack には、エラーが作られた時点の呼び出しの履歴が文字列で入っています。Node.js公式ドキュメントによると、この履歴はV8の仕組みに基づき、同期処理の開始地点まで、または Error.stackTraceLimit で決まるフレーム数のうち小さいほうまでしか含まれません。
つまり次の2点を押さえておくと読み間違いにくくなります。
- 上の行ほどエラーが作られた場所に近く、下の行ほど呼び出し元に近い。エラー生成位置と根本原因は一致するとは限らない。
- 長いトレースでも途中で切れていることがある。非同期処理では呼び出し元まで載らない場合もある。
なお、stack の書式はJavaScriptエンジンごとに違い、標準化されていないプロパティだとMDNは説明しています(Error: stack - MDN)。ここで示すのはNode.js(V8)形式の at 関数名 (ファイル:行:列) です。ブラウザのSafariやFirefoxでは見た目が違います。
2. 行の印付け例
説明用の例として、ECサイトのカート計算で出たエラーを想定します。各行の頭に印を付けました。
- 【自】自分のコード
- 【部】node_modules 内の部品(ライブラリ)
- 【内】Node.jsの内部処理(この例では node:internal/)
- 【言】言語組み込み(この例では Array.map)
<anonymous> は匿名関数などにも現れるため、この表記だけで言語組み込みとは判断しません。
/Users/demo/shop-app/src/price.js:12
return item.price * item.qty;
^
TypeError: Cannot read properties of undefined (reading 'price')
【自】 at calcLine (/Users/demo/shop-app/src/price.js:12:15)
【自】 at /Users/demo/shop-app/src/cart.js:8:30
【言】 at Array.map (<anonymous>)
【自】 at sumCart (/Users/demo/shop-app/src/cart.js:8:22)
【自】 at handleCheckout (/Users/demo/shop-app/src/routes/checkout.js:21:15)
【部】 at Layer.handle [as handle_request] (/Users/demo/shop-app/node_modules/express/lib/router/layer.js:95:5)
【部】 at next (/Users/demo/shop-app/node_modules/express/lib/router/route.js:149:13)
【内】 at process.processTicksAndRejections (node:internal/process/task_queues:95:5)(印は説明のために付けたもので、実際の出力には出ません)
読む順番
- メッセージ:undefined の price を読もうとして失敗した、とあります。つまり item が undefined です。
- 最初の【自】の行:price.js の12行目が、エラーが起きた場所です。
- 次の【自】の行:calcLine の呼び出し元は cart.js の8行目です。引数をどう作って渡したか、ここも見ます。
- 【部】【内】の行は呼び出し経路を示します。ただし、この表示だけで部品側に原因がないとは判断できません。
この例では、price.js の12行目を直すより、cart.js で undefined の要素が混ざる理由を調べるほうが本筋かもしれません。AIには、この2か所をセットで見せる必要があります。
3. AIに渡す抜粋範囲の判断表
トレースの形ごとに、渡す範囲を決める表です。編集上の目安なので、状況に応じて足し引きしてください。【部】【内】も原因候補に関係する場合や、判断に迷う場合は残します。共有前に第5節の確認を行ってください。
- 最初の at が【自】、渡すもの:メッセージ、【自】の行すべて、各行の関数本体、入力データの形、省いてよいもの:【部】【内】の残り行(省略した旨は書く)
- 最初の at が【部】で、すぐ下に【自】、渡すもの:メッセージ、最初の【部】行、その下の【自】の行と呼び出し部分のコード、ライブラリ名とバージョン、省いてよいもの:深い位置の【部】【内】
- 【自】が1行もない(【部】【内】だけ)、渡すもの:トレース全体、実行コマンド、起動直後に動くファイル(エントリポイント)、省いてよいもの:なし。削らない
- トレースが短い・途中で切れている、渡すもの:全体、await や setTimeout を使っている箇所のコード、省いてよいもの:なし
- 原因情報が付いている(cause あり)、渡すもの:外側のメッセージとトレース、cause の内容(エラーならそのメッセージとトレースも)、省いてよいもの:重複する【部】行(省略した旨は書く)
- dist/ など変換後のパスが出る、渡すもの:変換前の該当ファイルとの対応、または後述のソースマップ設定後の出力、省いてよいもの:変換後コードの全文
- ログ全体が数百行、渡すもの:問題の操作に対応するエラーの塊と、関連する前後のログ、省いてよいもの:無関係と確認できた警告や重複出力(関連が不明なら残す)
cause(原因エラー)がある場合
new Error("...", { cause: err }) では、指定した err が cause に入ります(Error: cause - MDN)。元のエラーを保持して文脈を加えるために使えますが、cause は自動で付くとは限らず、エラー以外の値も指定できます。表示形式は環境により違うため、外側のメッセージとトレースに加え、cause の内容も確認して一緒に渡してください。
TypeScriptなどを変換している場合
変換後のファイルが出力に出るなら、ソースマップが生成され、Node.jsから参照できることを確認して、--enable-source-maps を試します(Node.js CLIドキュメント)。元のソース位置の表示は保証されず、Error.prepareStackTrace の上書きが妨げになる場合もあります。また公式は、この設定を有効にして Error.stack にアクセスすると遅延が生じる場合がある、と注記しています。頻繁にアクセスする運用では性能への影響も確認してください。
トレースが短すぎるとき
フレーム数の上限は --stack-trace-limit=50 のように指定して増やせます(同じCLIドキュメント)。【自】の行が見つからず、上限で切れているように見えるときだけ試してください。
4. そのまま使える依頼文
下の文面の 【 】 を埋めて使います。入力例は、前節の説明用の例に合わせています。
Node.jsのアプリで次のエラーが出ます。原因の候補を挙げ、最小の修正案を出してください。
■ 環境
Node.js【バージョン】、express【バージョン】、実行コマンド:node src/server.js
■ エラー(部品側の行は省略しています)
TypeError: Cannot read properties of undefined (reading 'price')
at calcLine (src/price.js:12:15)
at src/cart.js:8:30
at sumCart (src/cart.js:8:22)
at handleCheckout (src/routes/checkout.js:21:15)
...(express内部が数行続く)
■ 該当コード
【price.js の calcLine 関数】
【cart.js の sumCart 関数】
■ 入力データの形(個人情報は架空の値に置換済み)
cart.items = [{ price: 100, qty: 2 }, undefined]
■ 依頼
1. 原因の候補を可能性の高い順に2〜3個。根拠は上のコードの行番号で示してください。
2. 修正は、calcLine側とsumCart側のどちらで行うべきか理由つきで。
3. 修正後に確認するテスト入力を1つ。
4. 渡した情報だけでは判断できない点があれば、推測せず質問してください。「推測せず質問してください」と依頼しても、回答が推測を含まない保証はありません。根拠に挙げられたコードを確認してください。
5. 貼る前と、直した後の確認
貼る前
- パスにユーザー名や社内のディレクトリ名が入っていないか。入っていれば /Users/demo/ のように置き換えます。
- エラーメッセージにトークン、接続文字列、メールアドレス、URLのクエリが含まれていないか。含まれていれば伏せ字にします。
- 省略した部分は「省略した」と明記します。黙って削ると、AIは「元からその構造だった」と読んでしまいます。
AIの回答を受け取った後
人が確認するのは次の3点です。
- AIが挙げた行番号が、手元のファイルの実際の行と一致しているか(違えば、古いコードや想像で答えている可能性があります)。
- 修正を入れて、元のエラーを起こした操作をもう一度実行し、同じエラーが消えたか。
- 別の入力(空の配列や1件だけのデータなど)でも壊れていないか。
エラーが消えても、undefined を単に無視する修正だと、原因である「なぜ混ざったか」が残ります。AIの案が値を握りつぶすだけの内容なら、前節の依頼の2番を使って、どの層で直すべきかを聞き直してください。
6. 迷ったときの最小ルール
- 自分で管理するソースファイルの行が見つかれば、その行と、呼び出し元に当たる【自】の行を一緒に渡す。
- 見つからなければ秘密情報を伏せ、トレース全体を渡す。
- 部品側の行を省くときは「省略」と書く。
この3つを出発点にして、情報が足りなければ抜粋範囲を広げます。

