こんにちは!Kredo Blog編集部のさおりです!
JSON.parse()で止まったとき、エラーを消すために引用符やカンマを一括で置き換えていませんか。読めるようになっても、中身を変えてしまったり、必要な項目が足りないまま先へ進んだりすることがあります。
まず確かめたいのは、何の文字列を読んでいるか、JSONの書き方に合っているか、読み取った値がアプリで必要な形かの三つです。例えばnullは正しいJSONですが、記録の一覧として使える配列ではありません。この違いが分かると、直す場所を絞れます。
この記事では、学習内容と時間を読み取る小さな教材を使います。末尾カンマのある入力、数値を文字列にしてしまった入力などを実際に試し、修正前後の結果まで確認していきましょう。
JSON.parseのエラーは、読み込む文字列から確かめる

JSON.parse()はJSON形式の文字列をJavaScriptの値へ変換します。JSONの構文として読めない文字列を渡すと、SyntaxErrorになります。まずは一つの記録だけで試してみます。出典:MDNのJSON.parse()
const text = '{"title":"英単語","minutes":20}';
const record = JSON.parse(text);
console.log(JSON.stringify(record));
結果は{"title":"英単語","minutes":20}です。外側のシングルクォートはJavaScriptの文字列を囲む記号で、その中にあるJSONの項目名や文字列はダブルクォートで囲んでいます。JavaScriptの書き方と、JSONそのものの書き方を分けて考えましょう。
うまくいかない場合は、入力の先頭だけでも見てください。空文字列、途中で切れた内容、HTMLのエラーページなど、JSONではないものを読もうとしていることがあります。APIや保存先を使う処理なら、「どこから得た値か」まで戻って確認します。
| 確認する段階 | 確かめることと次の行動 |
|---|---|
| 入力 | 読んでいる値は何か。空や未取得なら、データを取得する側を確認する。 |
| JSONの構文 | 引用符、カンマ、括弧などが正しいか。問題のある短い文字列で再現する。 |
| 読み取った値の形 | 必要な配列・項目・型があるか。アプリ側の条件と照合する。 |
実際のデータを調べるときは、認証情報や個人情報をそのまま外部サービスへ貼らず、問題が残る小さな架空データに置き換えます。最小再現コードの作り方も、原因を絞る際に役立ちます。
末尾カンマ・引用符・途中切れを、小さな例で直す
最後の要素の後ろにカンマを付けない
次の文字列には、配列の最後の要素と閉じ括弧の間に、余分なカンマがあります。この例は意図的に失敗させるコードです。
try {
JSON.parse('[{"title":"英単語","minutes":20},]');
} catch (error) {
console.log(error.name);
}
出力はSyntaxErrorです。直すのは},]のカンマ1文字。JSONの中のカンマをすべて消すと、今度は項目や要素の区切りまで失われます。
const records = JSON.parse('[{"title":"英単語","minutes":20}]');
console.log(records[0].minutes);
このコードは20を表示します。外側が配列になったので、最初の記録をrecords[0]で取り出しています。MDNのJSON構文エラーの説明でも、末尾カンマや引用符などの例を確認できます。
エラー文だけで原因を決めつけない
Unexpected tokenは、想定しない文字などに出会ったときの手がかりです。エラーに<が含まれていたら、HTMLを受け取った可能性もあります。ただし、文字一つだけで「必ず404」とは判断できません。受け取った内容とURL、HTTPの状態などを確認します。
Unexpected end of JSON inputのような表示なら、空の文字列や途中で切れた内容も候補になります。エラー文や位置の表現は実行環境で変わるため、同じ文言を探すだけでなく、実際の入力と括弧・引用符の対応を見ます。
| 入力の違い | 確認・修正する箇所 |
|---|---|
| 末尾カンマ | [1,2,]は最後のカンマを外して[1,2]にする。 |
| シングルクォート・項目名の引用符なし | JSON内は{"title":"英単語"}のように、項目名と文字列をダブルクォートで囲む。 |
| 途中で切れている | 閉じ括弧を当てずっぽうで足さず、コピーや取得の途中で欠けていないか元と照合する。 |
| コメントや文字列内の生の改行 | 通常のJSONにはコメントを入れない。文字列内の改行はJSONのエスケープ表現を使う。 |
| HTML・説明文・コードフェンス | 必要なJSONの範囲や取得先を確認する。HTMLを引用符の置換で直そうとしない。 |
JSONの文法は、JavaScriptのオブジェクトをそのまま書く場合とは異なります。文字列・数値・真偽値・null・オブジェクト・配列を表せますが、関数などを任意に書ける形式ではありません。出典:RFC 8259
読み込めても、アプリで使える形とは限らない

ここが、エラーの修正で見落としやすいところです。次の三つはどれもJSONとして読み取れます。ところが、配列かどうかを調べると結果は異なります。
for (const text of ['null', '{}', '[]']) {
const value = JSON.parse(text);
console.log(text, Array.isArray(value));
}
出力は順にnull false、{} false、[] trueです。JSON.parse()が成功しても、結果が一覧として使える配列だとは限りません。配列の確認にはArray.isArray()を使えます。出典:MDNのArray.isArray()
今回の教材では、次の形を期待することにします。これは教材のために決めた条件で、JSON全体の規則ではありません。
| 教材で決めた条件 | 採用する値・止める値 |
|---|---|
| 一番外側は配列 | []は0件として使う。nullや単体のオブジェクトは、この教材では止める。 |
| 各要素は記録のオブジェクト | nullや配列を記録として扱わない。 |
| titleは空でない文字列 | 空白だけの内容や、文字列ではない値を止める。 |
| minutesは0〜1440の整数 | 数値の0を残す。文字列の"20"、負数、小数、1441以上は止める。 |
| 追加の項目 | noteなどがあっても、この教材ではtitleとminutesだけを確認・集計する。 |
0分を許すのは、今回「まだ学習していない記録」を表せるようにしたためです。別のアプリが1分以上を求めるなら、その仕様に合わせます。数値文字列を自動変換するか、空配列を許すかも、先に決めておきましょう。
なおtypeof nullは"object"になります。「typeofがobjectなら記録」とするだけでは不十分です。次のコードではnullと配列を除いてから項目を見ています。
構文とデータの形を分けて確認するコード
読み取る関数は、結果をinput(入力)、syntax(構文)、shape(形)、ok(成功)に分けて返します。これらの名前は教材独自の区分です。try...catchをJSONの解析部分に絞り、後続処理の問題まで同じ「JSONが壊れた」にまとめないようにしています。
function checkRecords(text) {
if (typeof text !== 'string' || text.trim() === '') {
return { ok: false, stage: 'input', message: 'JSON文字列を入力してください。' };
}
let records;
try {
records = JSON.parse(text);
} catch (error) {
if (!(error instanceof SyntaxError)) throw error;
return {
ok: false,
stage: 'syntax',
message: 'JSONの構文を確認してください。',
detail: error.message
};
}
if (!Array.isArray(records)) {
return { ok: false, stage: 'shape', message: '一番外側を配列にしてください。' };
}
for (let i = 0; i < records.length; i += 1) {
const row = records[i];
const valid = row !== null && typeof row === 'object' &&
!Array.isArray(row) &&
typeof row.title === 'string' && row.title.trim() !== '' &&
Number.isInteger(row.minutes) && row.minutes >= 0 && row.minutes <= 1440;
if (!valid) {
return {
ok: false,
stage: 'shape',
message: `${i + 1}件目のtitleとminutesを確認してください。`
};
}
}
return {
ok: true,
stage: 'ok',
count: records.length,
totalMinutes: records.reduce((sum, row) => sum + row.minutes, 0)
};
}
Number.isInteger()は値が数値型の整数かを確認するため、文字列の"20"を整数として通しません。その後で0以上・1440以下という教材の範囲を確認しています。出典:MDNのNumber.isInteger()
一件でも条件に合わなければ、件数や合計を返さずに止めます。勝手にその記録だけを除外したり、読めなかった入力を空配列へ置き換えたりしません。「本当に0件」と「読み込めなかった」を区別するためです。
上の関数の後に、次を続けて実行してみてください。
const samples = [
'[{"title":"英単語","minutes":20},]',
'null',
'[{"title":"英単語","minutes":"20"}]',
'[{"title":"英単語","minutes":20},{"title":"JavaScript","minutes":0}]'
];
for (const text of samples) {
const result = checkRecords(text);
console.log(JSON.stringify({
stage: result.stage,
count: result.count,
totalMinutes: result.totalMinutes
}));
}
実行結果:
{"stage":"syntax"}
{"stage":"shape"}
{"stage":"shape"}
{"stage":"ok","count":2,"totalMinutes":20}
2行目と3行目はJSONとしては読めていますが、この教材の形に合っていません。4行目だけが、2件・合計20分まで進みます。処理を先へ進めるかどうかは、okを確認してから決めます。
教材を動かし、直す前と後を比べる

コードを読むだけでは違いをつかみにくければ、入力を選んで試せる教材を使ってください。JSON文字列と診断結果が同じ画面に並び、元の入力を残したまま確認できます。
JSONの読み込みを実際に試す
デモ・確認コード・32ケース・練習問題をダウンロードする(ZIP)
解凍後、index.htmlをブラウザで開きます。保存やAPI呼び出しは行わない独立教材です。スクリプトを読み込めない環境向けのローカルHTTP手順もREADMEに記載しています。
- 「正常:2件で20分」を入力し、「構文と形を確認」を押す。2件・20分になることを確かめる。
- 「末尾カンマ」を選んで入力し直す。構文で止まることを確認し、最後の余分なカンマ1文字を手で外す。
- もう一度確認する。今度は1件・20分になる。入力例が最初の2件とは異なる点にも注意する。
- 「文字列nullはJSONとして有効」と「minutesが数値文字列」を試す。どちらも構文の次の、形の確認で止まる。
- 「全ケースを検証」を押し、期待結果と実際が一致するかを見る。自分で条件を変えたら、期待結果も見直す。
2026年10月6日に、Node.js v26.9.0とmacOSのChromeで、同じ32ケースが期待どおりになることを確認しました。ブラウザでは代表8入力を個別に操作し、末尾カンマを手で修正して成功へ変わること、確認しても入力が自動変更されないことも確かめています。
Node.jsがすでに使える方は、解凍したフォルダーで次のコマンドを実行できます。新しいパッケージの追加は不要です。
node run-tests.cjs
結果JSONのpassedとtotalがともに32なら、このケース群は合格です。教材には実行済みの結果も同梱しています。32ケースで確認したのは、この読み取り関数の条件です。巨大な入力、重複した項目名、すべてのブラウザ、通信・保存を含む本番アプリ全体まで確認したわけではありません。
既存の学習記録アプリへ組み込むときは、配布コードをそのまま貼らず、項目名やIDなどの仕様を合わせる必要があります。JavaScriptで学習記録アプリを作る教材はtopicやidも使うため、今回のtitleだけの記録とは別の形式です。
練習:どの段階で止まるか予想する
問題1:nullと空配列は同じ結果ですか?
入力欄にnullを入れた場合と、[]を入れた場合を比べてください。どちらもJSONとしては正しくても、教材の判定は同じでしょうか。
答え:nullは形の確認で停止、空配列は成功して0件・0分です。読み込み失敗を空配列へ置き換えてしまうと、この差が見えなくなります。
問題2:時間の型だけを直してみましょう
[{"title":"復習","minutes":"0"}]は、構文の確認と形の確認のどちらで止まりますか。時間を0分の数値にするには、どこを変えればよいでしょうか。
答え:形の確認で止まります。"0"を0へ変えると、1件・0分になります。titleの引用符まで外さないでください。
問題3:2件目が違うとき、1件目だけ合計しますか?
教材の「2件目の形が違う」を試してください。1件目は正しく、2件目のminutesだけが文字列です。
答え:今回は全体を止めて2件目を案内します。問題のある行を黙って捨てて20分と集計すると、元データが全部反映されたように見えるためです。行ごとの除外を許す設計にするなら、除外件数や理由を伝える仕様も必要になります。
JSON.parseのエラーでよくある質問
try…catchを付ければ、JSONは自動で直りますか?
直りません。解析の失敗を捕まえて、表示や次の処理を決めるためのものです。元の文字列や取得元を確かめ、必要な修正を行います。今回の教材も入力を自動では書き換えません。
fetchのresponse.json()にもJSON.parseを重ねますか?
response.json()はレスポンス本文をJSONとして解析し、JavaScriptの値を得る非同期のメソッドです。得られた値へ、理由なくもう一度JSON.parseをかける必要はありません。HTMLが返ったなど、本文をJSONとして解析できない場合はSyntaxErrorになることがあります。通信の取得先や状態も別に確認します。出典:MDNのResponse.json()
引用符を一括置換すれば直せますか?
値の中にも引用符などが含まれるため、一括置換で意味を変えてしまうことがあります。JSONを生成する側を修正できるなら、手作業で文字をつなぐより、値をJSON.stringify()で文字列にする方法を検討します。受け取ったデータは控えを残し、修正後も内容を照合しましょう。
この関数だけで、どんなJSONでも安全に扱えますか?
今回決めた小さな学習記録の条件を確かめる関数です。大きなデータの上限、重複する項目名、業務上の制約、保存先、権限、画面へどう表示するかは別の設計になります。必要な仕様に合わせて確認を追加してください。
次は、同じエラーを直せるだけでなく、「どこで止まり、何を直すとどう変わったか」を自分の言葉で説明してみましょう。JavaScriptのサンプル集へ戻って小さな機能に組み込むと、読み取りと画面表示のつながりも確かめられます。
学ぶ順番や次の課題を相談する
英語とITをどのように学んでいくか迷っている方は、今できることと作りたいものを整理して、無料カウンセリングで相談できます。
英語でIT・AIを学べるKredo
英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?
当メディアを運営しているKredoは、英語×ITをオンラインで学ぶ「Kredoオンラインキャンプ」と、フィリピンのセブ島で英語とIT・AIを学ぶ「KredoIT留学」「KredoAI留学」を提供しています。これまでの卒業生は3,000名以上。卒業生の多くが、国内外のIT企業への転職、フリーランスなどへのキャリアチェンジを実現しています。これからの時代に必要な英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?









