B バイナンス · 世界最大級の暗号資産取引所バイナンス 登録 → AD OKX OKX · 世界の大手暗号資産取引所OKX 登録 → AD
💻 コーディングの基礎 · 第8講 / 10

デバッグとエラーの読み方 — 赤い文字を手がかりに変える

エラーメッセージは「名前: 説明」と行番号で、どこで何がおかしくなったかを教えてくれます。メッセージを最後まで読み、値を出力して確かめ、仮説を一つずつ消していけば、たいていのバグは思ったより早くつかまります。

⏱ 約22分 ✍️ 確認問題 5問 🧪 コード実習 4題 更新 2026-10-09
🎯 この講義の学習目標
  • エラーメッセージからエラー名・説明・行番号を見つけ、何が起きたかを言える
  • SyntaxError・ReferenceError・TypeError・RangeErrorのよくある原因を区別できる
  • console.logで値を追いながら、仮説を立てて確かめる手順でバグを見つけられる
  • エラーなしで結果だけが間違うバグや終わらない繰り返しに気づき、最小再現を作ってAIに質問できる

1.エラーメッセージは手がかりです

コードを書き始めたばかりのころは、赤いエラーがよく出ます。プロの開発者も同じです。違いは、エラーを見て慌てるか、手がかりとして読むかにあります。エラーを見つけて直す作業をデバッグといいますが、その第一歩はメッセージを最後まで、一文字ずつ読むことです。メッセージにはたいてい、直すべき場所の名前がそのまま書かれています。

JavaScriptのエラーメッセージはエラー名: 説明という形です。たとえばTypeError: Cannot read properties of undefined (reading 'length')は、「種類はTypeError(値の種類が合わない)、内容はundefinedからlengthを読もうとした」という意味です。この練習場は、実行中に起きたエラーなら何行目で起きたかも一緒に表示します。その行が出発点です。

知っておきたい点が二つあります。一つ目に、説明の文言はブラウザによって少しずつ違います。この講義のメッセージはクローム系のブラウザが使うV8エンジンの文言で、ほかのブラウザでは同じエラーが別の言い回しで出ることがあります。エラー名(TypeErrorなど)は言語の決まりで定められているので、ほとんどどのブラウザでも同じです。二つ目に、エラーが起きた行とミスをした行は違うことがあります。値がおかしく作られた場所は上のほうにあり、その値を使ったところで壊れたのが下のほう、ということがよくあります。

エラーが起きると、実行はその行で止まります。そのため、エラーより前のconsole.logは出力され、後ろのものは出力されません。この性質は「どこまで正しく動いたか」を教えてくれる手がかりになります。下のコードは、最初の行が出力されたあと3行目で止まります。

3行目で止まる — words[2]は存在しない要素なのでundefined
const words = ["りんご", "なし"];
console.log(words[0].length);
console.log(words[2].length);
console.log("ここは実行されない");
出力
3
TypeError: Cannot read properties of undefined (reading 'length')
  • エラー名 — どんな種類の問題か(SyntaxError、ReferenceError、TypeError、RangeError …)
  • 説明 — 何をしようとして行き詰まったか(どの名前、どのプロパティ)
  • 行番号 — どこで止まったか(ミスをした場所はそれより上かもしれない)

2.`SyntaxError` — そもそも実行されないエラー

SyntaxErrorは文法エラーです。かっこを閉じていない、カンマが抜けている、同じ名前を二回宣言した、といったように、コードがJavaScriptの文として読めないときに起きます。ほかのエラーと違って、コードを実行する前の読み込みの段階で引っかかるので、一行も実行されません。先頭にconsole.logを入れても何も出力されないなら、まず文法エラーを疑ってください。

この練習場は、文法エラーのときは行番号なしでメッセージだけを表示します。そのぶん、メッセージの中の手がかりが大切になります。missing ) after argument listは関数呼び出しの閉じかっこがないという意味で、Unexpected identifier 'price'は「priceが出てくるはずのない場所に出てきた」、つまりそのすぐ前にカンマなどが抜けているという意味です。Unexpected tokenが見えたら、その文字のすぐ前を調べます。名前が引用符で示されていれば、その名前で検索して場所を探すと早く見つかります。

文法エラーはたいてい、対応が合わないところで起きます。開きかっこ・波かっこ・引用符それぞれに閉じる相方があるかを確かめ、インデントをそろえてみると、対応がずれたところが目につきます。エディターが対応するかっこを強調してくれる機能も大いに役立ちます。長いコードを一度に書かず、数行ずつ書いて実行してみれば、文法エラーが出たときに今書いた数行だけを見れば済みます。

閉じかっこがない
console.log("こんにちは";
出力
SyntaxError: missing ) after argument list
priceのすぐ前、つまり上の行の末尾のカンマが抜けている
const item = {
  name: "りんご"
  price: 1500
};
出力
SyntaxError: Unexpected identifier 'price'
同じ名前を二回宣言
let count = 0;
let count = 1;
出力
SyntaxError: Identifier 'count' has already been declared
JSON文字列をJSON.parseで読むときに出るエラーも、名前はSyntaxErrorです。ただしこれはコードの文法ではなく「データの文法」が間違っているもので、実行中に起きるので行番号も表示されます。JSONが壊れているかどうかは、JSONフォーマッターに貼り付ければどこが間違っているかがすぐわかります。

3.`ReferenceError` — そんな名前はありません

ReferenceErrorは「その名前が見つからない」というエラーです。いちばん多い原因はタイプミスです。consoleをConsoleと書いたり、totalをtotlaと書いたりすると、JavaScriptはその名前の変数がないと教えてくれます。大文字と小文字も別の名前として扱われます。メッセージのis not definedの前にある名前をそのままコピーしてコードの中を検索すれば、つづりが違うところがすぐ見つかります。

二つ目の原因は「宣言する前に使う」ことです。let・constで作った変数を宣言した行より上で使うと、Cannot access 'price' before initializationになります。三つ目はスコープ(有効範囲)です。第5講で見たように、関数や{ }ブロックの中で作った変数はその外からは見えません。繰り返しの中で作った変数を、繰り返しが終わったあとで使おうとするとis not definedになります。

この練習場のように厳格モードで動くコードでは、letやconstなしで初めて見る名前に値を入れることもReferenceErrorになります。厳格モードでなければ、このミスは黙って新しいグローバル変数を作ってしまい、もっと見つけにくいバグになりますが、厳格モードはそれをすぐエラーとして知らせてくれます。

タイプミス — 名前をそのまま検索
const total = 100;
console.log(totla);
出力
ReferenceError: totla is not defined
宣言より先に使用
console.log(price);
const price = 1500;
出力
ReferenceError: Cannot access 'price' before initialization
ブロックの外からは見えない
for (let i = 0; i < 3; i++) {
  const last = i;
}
console.log(last);
出力
ReferenceError: last is not defined

4.`TypeError` — その値ではできないこと

TypeErrorは値の種類に合わないことをさせたというエラーで、初心者のうちにいちばんよく出会います。代表はCannot read properties of undefined (reading '…')です。undefinedやnullにはプロパティがないのに、ドット(.)をつけて何かを取り出そうとしたという意味です。かっこの中の名前が取り出そうとしたプロパティで、そのドットのすぐ左にある値がundefinedでした。

大事なのは「なぜその値がundefinedになったのか」です。JavaScriptは、存在しない配列の要素(arr[5])や存在しないプロパティ(user.nmae)を取り出すときにエラーを出さず、黙ってundefinedを返します。エラーが起きるのは、そのundefinedをもう一度使った瞬間です。だから、エラーの行のドットの左の値をconsole.logで出力してみて、その値がどこから来たのかを上へさかのぼる必要があります。犯人はたいてい、インデックスの範囲、プロパティ名のタイプミス、関数がreturnを書き忘れてundefinedを返した場合のどれかです。

もう一つよく見るのが… is not a functionです。関数ではないものをかっこ()で呼んだ場合で、メソッド名のタイプミス(toUppercase)か、別の種類の値にそのメソッドを呼んだかのどちらかです。たとえばtoFixedは数値のメソッドなので、文字列"1500"に対して呼ぶとこのエラーになります。第2講で見た型変換の問題とつながるところです。constで作った変数にもう一度値を入れたときのAssignment to constant variable.もTypeErrorです。

存在しないプロパティはundefined — エラーはその次に起きる
const user = { name: "健太" };
console.log(user.nmae);
console.log(user.nmae.length);
出力
undefined
TypeError: Cannot read properties of undefined (reading 'length')
メソッド名のタイプミス
const s = "hello";
console.log(s.toUppercase());
出力
TypeError: s.toUppercase is not a function
文字列にはtoFixedがない
const price = "1500";
console.log(typeof price);
console.log(price.toFixed(0));
出力
string
TypeError: price.toFixed is not a function
よく出会う四つのエラー(メッセージはV8エンジンの文言)
エラー名意味よくあるメッセージまず見るところ
SyntaxError文として読めないmissing ) after argument listかっこ・カンマ・引用符の対応
ReferenceErrorそんな名前はないx is not definedつづり・大文字小文字・宣言の位置・スコープ
TypeErrorその値ではできないことCannot read properties of undefinedドットの左の値がどこから来たか
RangeError値が許される範囲を外れたMaximum call stack size exceeded負の数・大きすぎる数・終わらない再帰

5.`RangeError`、そしてエラーにならないバグ

RangeErrorは、値の種類は合っているのに範囲がおかしいというエラーです。"*".repeat(-1)のように負の回数を渡したり、new Array(-1)のように負の長さを渡したりすると起きます。関数が自分自身を果てしなく呼び続けるとMaximum call stack size exceededになり、クローム系(V8)ではこれもRangeErrorです(ファイアフォックスは同じ状況をInternalError: too much recursionで知らせます)。関数が自分自身を呼ぶ再帰には、必ず止まる条件が必要です。

もっと厄介なのは、エラーにならないバグです。コードは最後まで動いたのに、結果だけが間違っている場合です。第4講で見たoff-by-one(一つずれ)が代表例です。i <= arr.lengthで繰り返すと、最後に存在しない要素を取り出してundefinedを足すことになり、数値にundefinedを足すとエラーではなくNaNになります。0で割るとInfinity、0 / 0はNaNになるだけで、エラーは出ません。結果にNaN・undefined・Infinityが見えたら、エラーメッセージがなくてもバグのサインです。

終わらない繰り返しもエラーメッセージを出しません。whileの条件がずっと真なら、プログラムはひたすら回り続けます。この練習場は、実行が2秒以内に終わらなければ強制的に止めて、時間制限にかかったと知らせます。その案内が出たら、繰り返しの終了条件を疑ってください。条件に使う変数が繰り返しの中で実際に変わっているか、終わりに近づく方向に変わっているかを見ます。実際のブラウザのタブで無限ループを回すとタブが固まることがあるので、繰り返しを書いたばかりのときは回数の少ない入力から試します。

範囲を外れた値
function stars(n) {
  return "*".repeat(n);
}
console.log(stars(3));
console.log(stars(-1));
出力
***
RangeError: Invalid count value: -1
エラーなしでNaN — off-by-one
const nums = [10, 20, 30];
let sum = 0;
for (let i = 0; i <= nums.length; i++) {
  sum += nums[i];
}
console.log(sum);
console.log(10 / 0, 0 / 0);
出力
NaN
Infinity NaN

6.デバッグの手順 — 出力し、仮説を立て、絞り込む

デバッグには決まった手順があります。まず「期待した結果」と「実際の結果」を一文ずつ書き出します。次に原因について仮説を一つ立て(例:繰り返しが一回多く回っている)、それを確かめられるいちばん小さな実験をします。仮説が正しければ直し、間違っていればそれを消して次の仮説に進みます。何か所も同時に変えると、どれが直したのかわからなくなるので、一度に一つだけ変えます。

いちばん手軽な実験道具はconsole.logです。怪しいところの値を出力してみれば、「頭の中の値」と「実際の値」がどこから食い違い始めるのかが見えます。繰り返しの中では番号と値を一緒に出力し、値の横にラベルをつければ(console.log("i:", i))、出力が混ざっても迷いません。typeofも一緒に出力すると、"1500"(文字列)と1500(数値)のように見た目が同じ値も区別できます。問題が見つかったら、確認用の出力は消します。

コードが長いときは最小再現を作ります。バグがそのまま現れる範囲で関係のない行を一行ずつ消していき、問題を起こすいちばん短いコードを残すことです。削っていく途中で原因が見えることも多く、人やAIに尋ねるときも、短いコードのほうがずっと的確な答えが返ってきます。説明しているうちに答えが見えてくることもあるので、コードを一行ずつ声に出して説明してみる方法(ラバーダック・デバッグ)も広く使われています。

例題架空の売上記録から平均を出すコードがNaNを出力します。どうやって原因を探せばよいでしょうか。
const sales = [10, 20, 30];
let sum = 0;
for (let i = 0; i <= sales.length; i++) {
  console.log("i:", i, "値:", sales[i]);
  sum += sales[i];
}
console.log(sum / sales.length);
出力
i: 0 値: 10
i: 1 値: 20
i: 2 値: 30
i: 3 値: undefined
NaN
  1. ステップ1 期待と実際を書き出します。期待:20、実際:NaN。エラーメッセージはないので、結果だけが間違うバグです。
  2. ステップ2 仮説:「足している値の中に数値でないものが混じっている」。繰り返しの中でiとsales[i]を出力してみます。
  3. ステップ3 出力を見ると、i: 3のとき値がundefinedです。配列は0〜2番しかないのに、3番まで回っています。
  4. ステップ4 条件i <= sales.lengthをi < sales.lengthに直し、空の配列や要素一つの配列でも試します。
答え繰り返しの条件が一回多く回るようになっていて、undefinedを足していました。<に直せば20になります。

7.AIにエラーを尋ねるときに渡すもの

AIコーディングアシスタントは、エラーメッセージを説明し、直す方向を示すのにかなり役立ちます。ただし、受け取った情報の分しか正確になれません。「動きません、直してください」よりも、エラーメッセージの全文、問題が起きる最小のコード、期待した結果と実際の結果、実行環境(ブラウザ・エンジン)、すでに試したことを一緒に渡すほうが、ずっと的確な答えが返ってきます。エラーメッセージは要約せず、そのままコピーして貼り付けてください。翻訳したり縮めたりすると、大事な手がかり(名前・プロパティ・行番号)が消えてしまいます。

貼り付ける前に必ず取り除くべきものもあります。パスワード、APIキー、アクセストークン、実在の顧客の名前・電話番号のような個人情報は、コードやデータに紛れていても消して、偽の値に置き換えます。会社や学校のコードなら、外部のAIに貼り付けてよいかどうか、まずそこの規則を確かめます。この点は第10講でさらに詳しく扱います。

AIが直したコードを受け取ったら、そのまま信じずに確かめます。元のエラーが消えたか、期待した結果が出るか、空の配列や0のような境界値でも正しいかを、自分で実行してみます。AIはもっともらしいけれど間違った説明をすることがあり、エラーを隠すだけのやり方(例:問題の値を無条件に0に変える)で「直す」こともあります。なぜそう直したのか説明を求め、その説明がエラーメッセージと合っているかを吟味してください。

  • エラーメッセージの全文(名前・説明・行番号)— そのままコピー
  • 問題が現れるいちばん短いコード(最小再現)
  • 期待した結果と実際の結果
  • 実行環境(どのブラウザか、この練習場か など)と、すでに試したこと
  • パスワード・キー・実在の個人情報は抜いて偽の値に

📌 要点まとめ

  • エラーメッセージは「名前: 説明」と行番号で読む — 説明の文言はブラウザによって少し違うが、名前は同じ
  • SyntaxErrorは実行前に引っかかって一行も動かず、ReferenceErrorは名前の問題、TypeErrorは値の種類の問題、RangeErrorは範囲の問題
  • undefinedは黙って生まれ、あとで壊れる — エラーの行のドットの左の値がどこから来たかをさかのぼる
  • NaN・Infinity・終わらない繰り返しは、エラーメッセージなしでやって来るバグのサイン — 練習場は2秒たつと実行を止める
  • 期待・実際を書く → 仮説を一つ → console.logで確かめる → 最小再現、そしてAIにはメッセージ全文と短いコードを秘密情報抜きで渡す

✍️ 確認問題

まず自分で解いてから「解答と解説」を開いてください。

Q1. いちばん最初の行にconsole.log("開始")を入れたのに何も出力されず、エラーだけが出ます。まず疑うべきエラーは?

⭕ 正解です

❌ もう一度考えてみましょう

解答と解説
正解 ① SyntaxError

文法エラーは実行する前、コードを読み込む段階で引っかかるので、最初の行も実行されません。ほかのエラーは、エラーが起きた行の手前までは実行されます。

Q2. TypeError: Cannot read properties of undefined (reading 'name')の意味として正しいのは?

⭕ 正解です

❌ もう一度考えてみましょう

解答と解説
正解 ① .nameの前の値がundefinedだった

undefinedからnameを読もうとしたという意味です。ドットの左の値を出力してみて、それがなぜundefinedになったのかをさかのぼります。

Q3. [10, 20, 30]の合計をfor (let i = 0; i <= arr.length; i++)で求めるとどうなるでしょうか。

⭕ 正解です

❌ もう一度考えてみましょう

解答と解説
正解 ① エラーなしでNaNになる

最後に存在しない要素arr[3]を取り出してundefinedを足し、数値 + undefinedはNaNです。エラーメッセージなしで結果だけが間違うバグです。

Q4. AIにエラーを尋ねるときにいちばんよい方法は?

⭕ 正解です

❌ もう一度考えてみましょう

解答と解説
正解 ① エラーメッセージの全文と、問題が起きる短いコード、期待・実際の結果を一緒に渡す

メッセージはそのまま、コードは最小再現に縮めて渡します。要約すると手がかりが消えますし、秘密情報や実在の個人情報は消して偽の値に置き換えます。

Q5. 終わらないwhileの繰り返しを直すときに確かめる二つのことを書いてください。

解答と解説
解答例 条件に使う変数が繰り返しの中で実際に変わっているか、そしてその変化が条件が偽になる方向(終わり)へ向かっているかを確かめます。

たとえばwhile (n > 0)なら、繰り返しの中でnが減っていく必要があります。この練習場は2秒たつと実行を止めて、時間制限にかかったと知らせます。

🧪 コード実習

どの最初のコードにも、バグが一つずつ隠れています。まずそのまま実行してエラーメッセージや間違った結果を読み、原因を見つけて一か所だけ直し、テストを通してください。

コードはこのブラウザの中の隔離された場所でだけ実行され、サーバーには送られません。ネットワークには接続できず、2秒を超えると止まります。書き換えたコードはこのブラウザにだけ保存されます。Ctrl+Enter(⌘+Enter)で実行、Tabキーは空白2つ(Escの後のTabで次へ移動)。

JavaScriptが無効なので実行はできませんが、問題・最初のコード・自動チェックの内容・解答例はそのまま読めます。

1名前のタイプミスを直す

価格priceと割引率rate(例:0.1は10%)を受け取り、割引後の価格を返す関数discount(price, rate)です。実行するとReferenceErrorが出ます。メッセージに出てきた名前を見て直してください。

自動チェック
  • discount(10000, 0.1)期待値 9000
  • discount(5000, 0.5)期待値 2500
  • discount(3000, 0)期待値 3000
  • discount(0, 0.2)期待値 0
💡 ヒント

prise is not defined — その名前がどこにあるかを探して、引数の名前と比べてみてください。

解答例を見る
function discount(price, rate) {
  const off = price * rate;
  return price - off;
}

2存在しないメソッドを直す

文字列sをすべて大文字にし、末尾に"!"をつけて返す関数shout(s)です。実行するとTypeError: s.toUppercase is not a functionが出ます。原因を見つけて直してください。空文字列なら"!"を返します。

自動チェック
  • shout("hi")期待値 "HI!"
  • shout("Hello World")期待値 "HELLO WORLD!"
  • shout("あいう")期待値 "あいう!"
  • shout("")期待値 "!"
💡 ヒント

JavaScriptの名前は大文字と小文字を区別します。第7講で使ったメソッド名のつづりを一文字ずつ比べてみてください。

解答例を見る
function shout(s) {
  return s.toUpperCase() + "!";
}

3NaNになる平均を直す

数値の配列numsの平均を返す関数average(nums)です。空の配列なら0を返します。エラーは出ないのに結果がNaNになります。繰り返しの中でiとnums[i]を出力してみて、原因を探してください。

自動チェック
  • average([10,20,30])期待値 20
  • average([7])期待値 7
  • average([1,2])期待値 1.5
  • average([-5,5])期待値 0
  • average([])期待値 0
💡 ヒント

console.log("i:", i, nums[i]);を繰り返しの中に入れてみてください。最後に出力される値は何ですか。

解答例を見る
function average(nums) {
  if (nums.length === 0) return 0;
  let sum = 0;
  for (let i = 0; i < nums.length; i++) {
    sum += nums[i];
  }
  return sum / nums.length;
}

4終わらない繰り返しを直す

正の整数nを受け取り、nから1まで逆に数えた配列を返す関数countDown(n)です。例:countDown(3) → [3, 2, 1]、countDown(0) → []。最初のコードは終わらないので、練習場が2秒後に実行を止めます。繰り返しの終了条件を調べて直してください。

自動チェック
  • countDown(3)期待値 [3,2,1]
  • countDown(1)期待値 [1]
  • countDown(5)期待値 [5,4,3,2,1]
  • countDown(0)期待値 []
💡 ヒント

条件n > 0がいつか偽になるには、繰り返しの中でnがどう変わる必要があるでしょうか。

解答例を見る
function countDown(n) {
  const out = [];
  while (n > 0) {
    out.push(n);
    n--;
  }
  return out;
}

🤖 AIにはこう聞いてみましょう

コピーして [ ] の部分を自分の状況に書き換えて使います。答えはそのまま信じず、本文と比べて確かめましょう。

エラーメッセージの意味がわからないとき

JavaScriptを[ブラウザ/練習場]で実行したら、次のエラーが出ました:[エラーメッセージの全文をそのまま]。問題が起きるコードはこれです:[最小のコード]。このエラーが何を意味するのかやさしい言葉で説明し、私のコードのどの行のどの値が原因である可能性が高いかを順番に教えてください。すぐに答えを出す前に、私が`console.log`で確かめるべき場所を先に教えてください。

エラーはないのに結果が間違っているとき

次の関数はエラーなしで動きますが、結果が間違っています。入力:[入力]、期待した結果:[期待]、実際の結果:[実際]。コード:[最小のコード]。原因の仮説を2〜3個立てて、それぞれの仮説を確かめる`console.log`の位置を教えてください。直したコードを出すときは、何をなぜ変えたのかと、境界値(空の配列、0)のテストも一緒に出してください。

AIが直してくれたコードを検証するとき

あなたが直してくれたコードが元の問題を本当に解決したか確かめたいです。元のエラー:[メッセージ]、直したコード:[コード]。変えた行ごとに理由を説明し、エラーを隠すだけの修正(例:値を無条件に0にする)になっていないか自分で点検してください。このコードが失敗しうる入力も3つ挙げてください。

🧰 関連ツール

この講義で扱ったJSON・正規表現・テキストを、その場で確かめたり整えたりできるツールです。本物の個人情報やパスワードは貼り付けないでください。

参考
  • MDN Web Docs — JavaScriptエラーリファレンス(JavaScript error reference)
  • MDN Web Docs — SyntaxError、ReferenceError、TypeError、RangeError
  • MDN Web Docs — 厳格モード(Strict mode)
  • Chrome DevToolsドキュメント — JavaScriptのデバッグを始める

学習目標をすべて達成できたら完了を押しましょう。

💻 コーディングの基礎

  1. 1プログラムとは — 仕事を順番・条件・繰り返しに分ける考え方
  2. 2値・変数・データ型 — 名札を付けて値を扱う
  3. 3条件分岐 — 状況によって違う道を進む
  4. 4繰り返し — 同じことを正確に何度もさせる
  5. 5関数 — 名前を付けた小さな機械に分ける
  6. 6配列とオブジェクト — データを入れて扱う
  7. 7文字列とテキスト処理 — 文字を切り出し、探し、置き換える
  8. 8デバッグとエラーの読み方 — 赤い文字を手がかりに変える
  9. 9かんたんな自動化の例 — 表の計算とテキストの整理をコードで
  10. 10AIが書いたコードを読んで検証する — テスト・セキュリティ・ライセンス・個人情報
📚 あわせて読みたい
📊表計算の作業を人工知能で手伝わせる、数式は必ず検証→ 💻人工知能のコーディング支援の使い方と危険、セキュリティとライセンス→ 💬外国語の会話練習相手としてAIを使う→ ⚙️業務自動化のアイデア探し、AIに任せる仕事の選び方→
← AI時代の基礎学力講座