JSON Toolkit

JSON エラーメッセージ早見表:エラー文言から修正まで直行

要点:JSON.parse の正確なメッセージから原因を引きます。Chrome・Firefox・Safari にまたがる 12 の頻出エラー、HTML エラーページ、途中切れ、二重パースを含みます。

中級約 8 分で読めます2026-10-30 公開2026-11-04 更新
JSON エラーメッセージ早見表のカバー画像

要点:JSON.parse のエラーが出たら、まず position と token を拾いましょう。position が 0 なら HTML レスポンス・BOM・型違いを疑い、「Expected」のメッセージなら前の文字を見ます。報告された位置から行ごとに読み直すのはやめましょう。

エラー文言は雑音ではありません。答えそのものです。パーサーはぶつかった文字、期待していたもの、実際に受け取ったものを教えてくれます。エラーメッセージで検索する方が、文書全体を手で書き直すより速いのです。

JSON.parse() のエラーには必ず三つの要素があります。位置(文字オフセット、または行・列)、期待(Expected...)、現実(Unexpected token X、または xxx is not valid JSON)です。エンジンによって言い回しは異なります。Chrome と Node(V8)は Expected ',' or '}' after property value in JSON at position 25、Firefox は JSON.parse: expected ',' or '}' after property value in object at line 3 column 1、Safari は JSON Parse error: Expected ',' or '}' と言いますが、どれも同じ構文の破綻を指しています。エラーを調べるときは文言を無視し、三つの事実、つまりどの文字か、何を期待していたか、何が届いたかを拾ってください。

1. 12 エラー早見表

左列はコンソールから最も識別しやすい断片です(V8 の文言)。Firefox / Safari の変種は括弧内に示します。

エラー文言(V8) 実際の原因 修正
Unexpected token < in JSON at position 0 API が JSON ではなく HTML を返した(404 ページ、500 テンプレート、ログインリダイレクト、プロキシのフォールバック) 先に response.status と Content-Type を確認する。JSON を直さない
Unexpected end of JSON input 入力が空または途中で切れている。空のボディ、204、中断されたダウンロード、最終行を欠いたコピー 空の場合を処理し、Content-Length と比較して切れ目を探す
Unexpected token o / "[object Object]" is not valid JSON すでにパース済みのオブジェクトを再度 JSON.parse() に渡し、文字列に変換された typeof を確認する。オブジェクトならそのまま使う
"undefined" is not valid JSON 変数が一度も代入されていない(JSON.parse(undefined)) フォールバック値を初期化し、パース前にガードする
Expected double-quoted property name in JSON 末尾カンマ({"a": 1,})。パーサーは次のキーを期待し、} に出会う 最後の項目の後のカンマを削除する
Expected property name or '}' in JSON 引用符なしまたは単一引用符のキー({name: "Ada"}、{'name': 'Ada'}) すべてのキーを二重引用符で囲む
Expected ',' or '}' after property value in JSON カンマの欠落({"a": 1 "b": 2})、または値の後のコメント カンマを追加する。コメントを除去する
Unexpected token '/' JSON 内の // または /* */ コメント 削除するか、設定を JSONC としてパースする
Bad control character in string literal 文字列内の生の改行、タブ、その他の U+0000–U+001F 制御文字 \n と書く。JSON.stringify で生成する
Unterminated string in JSON " で開いた文字列が閉じられていない、または内側の引用符がエスケープされていない 内側の引用符を \" とエスケープする
Unexpected non-whitespace character after JSON 一つのテキストに二つの文書:{}{}、NDJSON、JSONP ラッパー 行で分割して個別にパースするか、NDJSON パーサーを使う
JSON.parse is not a function 独自の変数がグローバルの JSON を隠している 変数名を変更する。JSON という名前は使わない

最初の二つは詳しく見る価値があります。どちらも「あなたの JSON が間違っている」ではなく、「受け取ったものは思っているものと違う」という意味だからです。

2. position 0 エラーの三つのよくある原因

position が 0 なら、最初の文字が不正です。何も怪しく見えなければ、その文字は不可視である可能性が高いです。容疑者は三つ。

第一:<、つまり HTML。 本番で最もよくあるパースエラーです。URL の誤り、期限切れセッションのゲートウェイによるリダイレクト、サーバーエラーテンプレート。ボディが <!DOCTYPE html> で始まり、パーサーは一文字目で止まります。正しい対応は Network パネルを開いて生のレスポンスを読み、JSON ではなく API 呼び出しを直すことです。

第二:BOM またはゼロ幅文字。 Windows のメモ帳で保存したファイルはしばしば UTF-8 BOM(\uFEFF)で始まり、Web ページやチャットアプリからコピーしたテキストはゼロ幅スペース(\u200B–\u200D)を含むことがあります。あなたには見えませんが、パーサーには明らかです。

// パース前に BOM とゼロ幅文字を除去する
const cleaned = raw.replace(/^\uFEFF/, '').replace(/[\u200B-\u200D]/g, '');
const data = JSON.parse(cleaned);

第三:型違い。 JSON.parse(undefined) は "undefined" is not valid JSON を報告し、JSON.parse(someObject) は Unexpected token o を報告します(オブジェクトが "[object Object]" に変換され、o が位置 1 で不正になります)。どちらも「データはすでにパース済み」または「そもそもデータがなかった」という意味です。構文ではなく型を確認してください。

let data = text;
if (typeof data === 'string') {
  data = JSON.parse(data); // 本当に文字列のときだけパースする
}

3. 位置は下流を指し、原因は上流にある

位置について誤解を招くエラーが二つあり、どちらも早見表で最も読み違えられる項目です。

  • カンマの欠落:{"a": 1 "b": 2} は "b" の行で Expected ',' or '}' after property value を報告します。報告は正しいのですが、修正すべき場所は前の行の末尾です。
  • 閉じ括弧の欠落:深いネストで } や ] が一つ足りないと、パーサーは入力の最後まで飲み込み、Unexpected end of JSON input を報告します。位置はファイル末尾ですが、本当の欠落はずっと前にあることがあります。直近の閉じていない { または [ を後方に探しましょう。対応を数える方が目視より確実です。

一般的な手法は二分探索です。報告された位置より前のテキストを切り出して単独でパースします。パースできれば問題は報告位置の近くにあり、できなければさらに前で二分します。最初に失敗する断片の境界が本当のエラー位置です。大きなファイルではまず整形してください。インデントが揃っていれば、足りない階層が一目で分かります(オンラインの JSON フォーマッタで十分です)。

4. パースは通るが挙動がおかしい四つの「見かけの正常」

エラーより厄介なのは、エラーが出ないのにデータが間違っている状態です。次の四つはいずれも JSON として正しく、パーサーは満足しています。問題はデータの形にあります。

  1. 二重エンコード:文書全体が二度 JSON.stringify され、パース結果がオブジェクトではなく文字列になる。typeof result === 'string' ならもう一度パースしますが、根本では二重シリアライズを見つけて直してください。
  2. 重複キーが無言で上書き:{"name": "Tom", "name": "Jerry"} は正しい JSON で、ほとんどのパーサーは文句を言わず、後ろの値が勝ちます。複数ソースのデータを統合するときに刺されます。刺される前に厳格な JSON バリデータで表面化させましょう。
  3. NDJSON を一文書として扱う:ストリーミング API は 1 行に 1 オブジェクトを出力します。テキスト全体をパースすると Unexpected non-whitespace character after JSON で失敗します。\n で分割し、行ごとにパースします。
  4. 数値精度の静かな損失:2^53 - 1 を超える整数(スノーフレーク ID)は、末尾の桁がゼロになり、エラーは一切出ません。ID は文字列で送ります。

共通するのは、パーサーはすべて正常だと信じていることです。ですから API のデータがおかしく見えたら、まず生テキストの先頭 80 文字と typeof を出力し、内容の議論の前に形を確認してください。

5. 書き込み時にエラーを起こりにくくする

早見表は事後の道具で、予防は事前の道具です。四つの習慣がほとんどのエラーを発生前に食い止めます。

// 1. レスポンスをパースする前の二つの確認
const response = await fetch('/api/users');
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: API がデータを返しませんでした`);
}
const contentType = response.headers.get('content-type') ?? '';
if (!contentType.includes('application/json')) {
  throw new Error(`JSON を期待しましたが、${contentType} を受け取りました`);
}
const data = await response.json(); // 2. json() がすでにパースする。再度パースしない
  • 連結ではなくシリアライズで生成する:JSON.stringify() は引用符、改行、制御文字を正しく処理します。手組みの文字列は Bad control character と Unterminated string の最大の発生源です。
  • 必ず catch する:投げられた JSON.parse エラーは、誰かが捕まえない限り同期的なクラッシュです。localStorage や外部ファイルのような信頼できない入力では、catch ブロックに既定値か明示的なエラー報告が必要です。
  • 構造は Schema に任せる:構文が正しいことは構造が正しいことを意味しません。フィールド欠落や型違いは境界での JSON Schema 検証の仕事です。JSON Schema が解決するものを参照してください。

6. 素早い判断経路

記事全体を一つの判断順に圧縮します。エラーを見たら、まず position と token を拾います。

  1. position が 0 → <(HTML)、BOM、型違いの三つを確認。
  2. end of input → 空または切れたボディを確認し、閉じていない括弧を後方に探す。
  3. Expected ... → 前の文字を見る。たいていカンマか引用符の欠落。
  4. after JSON data → 複数の文書が連結されている。行で分割。
  5. パースは通るがデータがおかしい → 四つの「見かけの正常」チェックを実行。

JSON パースエラーの直し方の段階的な切り分けと組み合わせれば、パース問題の 90% は五分以内に解決します。エラー文言そのものをブックマークしておきましょう。それはパーサーがあなたのために書いたデバッグログで、言い回しは三年に一度変わる程度。一度引けば一年分の価値があります。

「Unexpected token in JSON」とはどういう意味ですか?

パーサーが、JSON 文法上その位置では不正な文字にぶつかったという意味です。token は拒否された文字です。< は通常 API が HTML を返したこと、' は単一引用符、/ はコメント、普通の英字は引用符なしキーや undefined、NaN のような JavaScript 専用リテラルを意味します。まず token、次に position を読み、原因を一つに絞り込みます。

「Unexpected end of JSON input」はどう直しますか?

原因は二つ。空の入力(空のレスポンスボディ、localStorage の空文字列)か、切れた入力(中断されたダウンロード、最終行を欠いたコピー、サイズ制限)です。空の場合は if (!text) return で処理し、その後で完全性を確認し、直近の閉じていない {、[、" を閉じます。深い階層の括弧欠落でもこのエラーが出ることがあり、位置がたまたまファイル末尾なだけです。

Chrome、Firefox、Safari でエラーが違うのはなぜですか?

三つのブラウザは異なる JS エンジン(V8、SpiderMonkey、JavaScriptCore)を積んでおり、それぞれ独自の言い回しでエラーを出します。MDN が公式の変種をすべて記録しています。しかし三つのエラーは位置・期待・現実という同じ三要素を、一対一の意味で運んでいます。V8 の文言に翻訳して、この早見表をそのまま使ってください。

エラー位置が正常に見える場所を指しているときは?

本当のエラーはもっと前にあります。典型例はカンマの欠落(次の行で報告)と閉じ括弧の欠落(ファイル末尾で報告)です。報告位置から token 単位で後方に辿るか、二分探索します。前半だけをパースし、最初に失敗する断片の境界が真のエラー位置です。