JSONの "Unexpected token" エラーを直す
JSON.parse で SyntaxError: Unexpected token ... in JSON at position Nが出たときの原因を、position N の読み方から系統立てて解説します。
This guide explains why JSON.parse throws "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 |
|---|---|---|
Expected double-quoted property name in JSON at position N | 末尾カンマ / Trailing comma | 最後のカンマを削除 / Remove it |
Expected property name or '}' in JSON at position N | シングルクォート / Single quotes | 全てダブルクォートに / Use double quotes |
"undefined" is not valid JSON | 値が undefined / Value is undefined | response ?? "null" で fallback |
Unexpected token '', "..." is not valid JSON (不可視) | BOM / UTF-8 BOM | s.replace(/^\uFEFF/, "") |
Unexpected token 'N', "..." is not valid 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 を検査し、その後にパースします。ログへ本文全体を出すと個人情報やトークンが漏れる可能性があるため、必要な範囲だけを安全に記録してください。
このサイトの自動診断ツールが見ているポイント / What our error diagnoser checks for
この記事の上部に埋め込まれている JsonErrorDiagnoser は、先頭のBOM文字(charCodeAt(0) === 0xfeff)、オブジェクトや配列の閉じ記号直前の末尾カンマ、シングルクォート、// や /* */ 形式のコメント、NaN・Infinity・undefined といった無効なリテラル、クォートされていないキー名を検知します。さらに、文字列の閉じ忘れや閉じ括弧の不足など、構造の不整合も原因候補として調べます。
ダブルクォートで囲まれた文字列の中身は判定対象から除外し、文字列内にたまたま ,} のような並びがあっても末尾カンマと誤判定しないようにしています。また、原因を1つに断定するのではなく、該当した複数の候補を検出順に提示する設計です。
The embedded JsonErrorDiagnoser checks for BOMs, trailing commas, single quotes, comments, invalid literals, unquoted keys, unterminated strings, and missing closing brackets. It ignores content inside double-quoted strings to reduce false positives and reports every matching candidate in detection order instead of asserting a single cause.
6. English summary
JSON.parse throws Unexpected token ... in JSON at position N when 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.
よくある質問 / FAQ
- Unexpected token の position N は何を指す?
- 入力文字列の0始まりのコードポイントインデックスです。改行やBOMも1文字としてカウントされます。
- What does 'position N' in the error mean?
- It is a zero-based index into the input string. Newlines and the BOM count as characters too.
- 末尾カンマを許容したい
- JSONは末尾カンマを許容しません。JSON5 や JSONC(VS Code)を使うか、パース前に正規表現で除去します。