JSONの "Unexpected token" エラーを直す
JSON.parse で SyntaxError: Unexpected token ... in JSON at position Nが出たときの原因を、position N の読み方から系統立てて解説します。
This guide explains why JSON.parsethrows "Unexpected token ... at position N" and walks through the most common causes (trailing commas, single quotes, undefined, BOM, NaN).
TL;DR
position Nはインデックス番号。エディタで該当位置に飛ぶとほぼ確実に原因が見える- 最頻出は 末尾カンマ、シングルクォート、
undefinedの混入 - 0番目で失敗するなら BOM か 空文字列 を疑う
JSONエラーを診断
JSON文字列またはエラーメッセージから、よくある原因と修正方法を推測します。
1. position N の読み方 / How to read "position N"
position の N は、入力文字列の 0始まりのコードポイントインデックス。 改行・タブ・BOM も 1 文字としてカウントされます。VS Code なら Ctrl+G → 目的行へジャンプし、 列番号を N から換算すれば一発で特定できます。
N is a zero-based character index, counting newlines and BOM. Jump to it in your editor.
コンソールでの見え方
APIがJSONではなくHTMLのエラーページを返すと、DevTools Consoleでは次のように表示されます。先頭の < と <!DOCTYPE が、HTMLをJSONとして読もうとした証拠です。
Uncaught SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
at JSON.parse (<anonymous>)
at loadUser (app.js:24:18)
^ 呼び出し元の行を確認
^ '<!DOCTYPE' はHTMLが返った証拠
// Networkタブでも Content-Type と本文を確認する
// 想定: application/json
// 実際: text/htmlこの場合、JSON文字列の修正だけでは解決しません。Networkタブでステータスコード、Content-Type、レスポンス本文を確認し、APIのURL間違い、認証切れ、サーバー側のエラーページなどを直します。response.json() の前に response.ok を確認するのも有効です。
2. 代表的な原因と対処 / Common causes
| 症状 / Symptom | 原因 / Cause | 対処 / Fix |
|---|---|---|
Unexpected token , in JSON at position N | 末尾カンマ / Trailing comma | 最後のカンマを削除 / Remove it |
Unexpected token ' in JSON | シングルクォート / Single quotes | 全てダブルクォートに / Use double quotes |
Unexpected token u in JSON at position 0 | 値が undefined / Value is undefined | response ?? "null" で fallback |
Unexpected token in JSON at position 0 (不可視) | BOM / UTF-8 BOM | s.replace(/^\uFEFF/, "") |
Unexpected token N in JSON | NaN / Infinity を書いた / Non-JSON numbers | null に置換 / Replace with null |
Unexpected end of JSON input | 閉じ括弧不足 / Truncated | ログ切れなら再取得 / Re-fetch source |
3. JavaScript値に起因する周辺パターン
localStorage.getItem() が null を返す
キーが存在しないと localStorage.getItem() は文字列ではなく null を返します。現代のブラウザでは JSON.parse(null) は null になりますが、値がないことを設定オブジェクトと取り違えると後続処理で失敗します。明示的に存在確認し、初期値を決めてください。
const stored = localStorage.getItem("preferences");
const preferences = stored === null
? { theme: "system" }
: JSON.parse(stored);Date オブジェクトを JSON.parse に渡す
JSON.parse が受け取るのはJSON文字列です。Dateオブジェクトを渡すと文字列化された日付をJSONとして解釈しようとしてエラーになります。Dateを保存するなら、先にオブジェクト全体を JSON.stringify し、復元後に日付文字列からDateを作り直します。
const text = JSON.stringify({ createdAt: new Date().toISOString() });
const data = JSON.parse(text);
const createdAt = new Date(data.createdAt);4. JSON Schema と Ajv で再発を防ぐ
パースできるJSONでも、必須項目の欠落や型違いまでは JSON.parse で検出できません。すでにAjvを利用するプロジェクトでは、パース後の値をJSON Schemaで検証すると、想定外のデータを業務処理へ渡す前に止められます。Ajv自体は不正なJSON文字列をパースするものではないため、JSON.parse の例外処理と組み合わせます。
import Ajv from "ajv";
const ajv = new Ajv();
const validate = ajv.compile({
type: "object",
properties: { id: { type: "integer" }, name: { type: "string" } },
required: ["id", "name"],
additionalProperties: false,
});
try {
const data: unknown = JSON.parse(responseText);
if (!validate(data)) {
console.error("Schema validation failed", validate.errors);
}
} catch (error) {
console.error("Invalid JSON", error);
}APIの送信側と受信側で同じスキーマを契約として管理すると、形式変更をテスト段階で検知しやすくなります。Ajvを未導入のプロジェクトでは、要件と既存構成を確認してから採用してください。本記事のために依存を追加する必要はありません。
5. 再発防止 / Prevention
- JSON は手書きせず
JSON.stringifyで生成する - VS Code の
.jsoncモードは末尾カンマを許容するが、JSON.parse には通らないことを意識 - API レスポンスは JSON Schema Validator で契約を固める
外部APIを読む場合は、まずHTTPステータスと Content-Type を検査し、その後にパースします。ログへ本文全体を出すと個人情報やトークンが漏れる可能性があるため、必要な範囲だけを安全に記録してください。
6. English summary
JSON.parse throws Unexpected token ... in JSON at position Nwhen the input contains something that isn't legal JSON. The position is a zero-based character index, counting newlines and BOM. The frequent offenders are trailing commas, single quotes, a literalundefined, a UTF-8 BOM at position 0, and NaN/Infinitywhich JSON doesn't allow. Jump to the index in your editor, identify the category, and apply the corresponding fix. For recurring issues, validate payloads with a JSON Schema.