PC・モバイルのトラブル

JSON.parseが「Unexpected token」と言うのはなぜ?

テキストが有効なJSONでないとき、JSON.parseはUnexpected tokenを投げる。単引用符、末尾カンマ、HTML応答、エラー位置を切り分ける。

要点

入力が有効なJSONでないとき、JSON.parse()はSyntaxErrorを投げる。「Unexpected token」は、その位置の構造では許されない文字にパーサーが達した、という意味が多い。

よくある原因は、単引用符、末尾カンマ、引用符なしのプロパティ名、誤った文字列エスケープ、JSONの前後の余分なテキスト、HTMLなど非JSONの本体をJSONとして読むことだ。

正確なエラー文はJavaScriptエンジンとブラウザで違う。「Unexpected token X in JSON at position N」がどのランタイムでも出ると思い込まないこと。

これはJSON.parseのUnexpected tokenの切り分けだ。エラーの意味、positionの読み方、本体がHTMLのときの対処。末尾カンマ・引用符・Unexpected endの幅広い解説はよくあるJSONエラー:末尾カンマ、引用符、Unexpected tokenにある。

JSON.parse()の「Unexpected token」は何を意味するか?

JSON.parse()はJSONの文法を要求する。現在位置の不正な文字はSyntaxErrorになる。{“name”:“Alex”,} は無効だ。そのカンマのあと、オブジェクトは終われない。メッセージとpositionはランタイムでまだ違う。

JSON.parse()はどのエラーを投げるか?

無効なJSONはおおむねSyntaxErrorを投げる。型を確かめるにはerror.nameをログする。error.messageの全文をハードコードしないこと。エンジンと版で文言が違う。

try {
  JSON.parse('{"name":"Alex",}');
} catch (error) {
  console.log(error.name);
  // SyntaxError
}

1. 二重引用符の代わりに単引用符を使う

{‘name’:‘Alex’} は無効なJSONだ。{“name”:“Alex”} は有効だ。JSONの文字列とオブジェクトのメンバー名は二重引用符を使う。const user = { name: ‘Alex’ } のようなJavaScriptオブジェクトリテラルは、合法なJavaScriptでもJSONテキストではない。

無効

{'name':'Alex'}

有効

{"name":"Alex"}

2. 末尾カンマ

最後のプロパティや配列要素のあとのカンマは、標準JSONでは無効だ。{“name”:“Alex”,“age”:30,} も [1, 2, 3,] も失敗する。Unexpected tokenの原因の一つとして扱う。末尾カンマの詳しい話はよくあるJSONエラー:末尾カンマ、引用符、Unexpected tokenにある。

無効

{
  "name": "Alex",
  "age": 30,
}

有効

{
  "name": "Alex",
  "age": 30
}
[1, 2, 3,]

3. 引用符なしのプロパティ名

{ name: “Alex” } はJavaScriptのオブジェクトリテラルになり得る。JSONではオブジェクトのメンバー名は文字列であり、二重引用符が要る:{“name”:“Alex”}。

無効

{
  name: "Alex"
}

有効

{
  "name": "Alex"
}

4. 不正な文字列エスケープ

JSONテキストではバックスラッシュがエスケープの開始だ。C:\Users\Alex のような生のパスは無効で、\U は合法なエスケープではない。バックスラッシュを二重にする。ホスト言語の文字列エスケープとJSONのエスケープを混ぜない。詳しくはよくあるJSONエラー:末尾カンマ、引用符、Unexpected token。

無効

{"file":"C:\Users\Alex"}

有効

{"file":"C:\\Users\\Alex"}

5. JSONの前や後の余分なテキスト

JSON.parseはJSON値を一つ期待する。{“ok”:true} の前の Success: や、後ろの done があると、文字列全体が無効になる。一つのJSON値のまわりの意味のない空白は許される。値の前後にスペースがあること自体は、JSONで禁じられていない。

Success:
{"ok":true}
{"ok":true}
done

6. JSONの代わりにHTMLを解析する

HTMLページに対してresponse.json()を呼ぶのは、Unexpected tokenのよくある例だ。誤ったエンドポイント、404や500のHTML、ログインリダイレクト、プロキシの本体、フォールバックページは、マークアップで始まることが多い。「Unexpected token < は常にHTML」は言い過ぎだ。< は手がかりであり、証明ではない。

fetch('/api/data')
  .then(response => response.json())

「Unexpected token <」はたいてい何を意味するか?

JSON値はふつう < で始まらない。本体が や なら、< が最初の不正文字になり得る。ローカルの切り分けでは、HTTPステータス、Content-Type、生の本体を見る。エンジンの文言はなお違う。

解析する前に応答を確認する

fetchの本体は一度しか消費できない。ローカルの切り分けでは、先にtext()を読み、短い先頭を見て、同じ文字列をJSON.parseする。同じ応答でresponse.json()のあとresponse.text()を呼んではいけない。本番の機微なペイロードを既定でログしない。

const response = await fetch(url);
const text = await response.text();

console.log(response.status);
console.log(response.headers.get("content-type"));
console.log(text.slice(0, 200));

try {
  const data = JSON.parse(text);
  console.log(data);
} catch (error) {
  console.error("Invalid JSON:", error);
}

「at Position 123」は何を意味するか?

エンジンによってはposition、行、列を報告する。近くの誤った引用符、カンマ、波括弧、エスケープを見る。その番号は、解析が問題に気づいた位置だ。本当の原因はより手前にあり得る。故障した文字そのものとは限らない。

Unexpected token と Unexpected end

Unexpected tokenは、パーサーが予期しない文字に出会ったという意味だ。{“name”:“Alex” のように閉じ括弧がないなど、値が完了する前に入力が止まると Unexpected end が出ることがある。正確な文言はエンジン依存だ。不完全なJSONの広い話はよくあるJSONエラー:末尾カンマ、引用符、Unexpected tokenにある。

{"name":"Alex"

JSONはJavaScriptオブジェクトリテラルと同じではない

JSONはデータ形式だ。JavaScriptオブジェクトリテラルはJavaScriptの構文だ。引用符なしキー、単引用符、末尾カンマのあるJSオブジェクトは、有効なJSONテキストではない。JSON.parseはJavaScriptオブジェクトリテラルを安全に解析できない。

const data = {
  name: 'Alex',
  active: true,
};
{
  "name": "Alex",
  "active": true
}

JSONにコメントを含めてよいか?

標準JSONはコメントをサポートしない。オブジェクト内の // 行は無効だ。JSON5や類似の拡張は別形式だ。JSON整形・検証・比較はJSON.parseで標準JSONを検証し、JSON5をJSONとしては扱わない。

{
  // user name
  "name": "Alex"
}

undefined、NaN、Infinityは有効なJSONか?

いいえ。JSONの値はobject、array、string、number、true、false、nullだ。undefined、NaN、Infinityはそうではない。トップレベルの値はオブジェクトや配列でなくてよい。true、123、“hello”、nullは有効なJSONだ。

{"a":undefined}
{"a":NaN}
{"a":Infinity}
true
123
"hello"
null

Unexpected tokenエラーを順に直す方法

エラー文字列ではなく、ソースを扱う:

  1. 入力が本当にJSONか確認する。HTML、ログ、JavaScriptではないか。
  2. 生入力の先頭文字を見る。
  3. API由来なら、HTTPステータスとContent-Typeを見る。200でもapplication/jsonでも、有効なJSONは保証されない。
  4. JSONパーサーで構文を検証する。
  5. 報告されたposition、行、列は手がかりであり、保証された根本原因ではない。
  6. その付近の引用符、カンマ、波括弧、角括弧、エスケープを確認する。
  7. 整形され検証済みのコピーと比較する。
  8. シリアライザかエンドポイントを直す。報告されたトークンを無作為に消さない。
引用符を無作為に置き換えてJSONを「直す」な

' を " へ一括置換すると、文字列内のアポストロフィ、既にエスケープされたテキスト、非JSONのソースを壊し得る。本物のシリアライザから有効なJSONを出す。evalをJSONパーサーとして扱わない。

JavaScriptでJSONを出すときはJSON.stringify()を使う

手で文字列を連結するよりJSON.stringifyを優先する。シリアライズする値については有効なJSONテキストを出す。すべてのJavaScript値を保つわけではない。undefined、関数、シンボルには特別な挙動がある。その詳細はこの記事の範囲外だ。

const data = {
  name: "Alex",
  active: true
};
const json = JSON.stringify(data);
// {"name":"Alex","active":true}

無効なJSONと本当の修正

これらの対はJSON.parseで確認した。HTMLでは、修正は応答であり、構文の編集ではない。

問題 無効例 直し方
単引用符 {'a':1} {"a":1}
末尾カンマ {"a":1,} {"a":1}
引用符なしキー {a:1} {"a":1}
undefined {"a":undefined} {"a":null}
HTML本体 <html>... エンドポイントと生の応答を確認する。HTMLをJSONへ編集しない。

Unexpected tokenの簡単な判断ガイド

JSON.parseが失敗したら、引用符を書き直す前に、そもそもJSONがあるかを決める。

  • JSON.parseが失敗した
  • API由来か。ステータス、Content-Type、生の本体を確認する
  • JSONで始まっているか。そうでなければソースかエンドポイントを直す
  • そうなら、引用符、カンマ、波括弧、角括弧、エスケープ、未対応の値を検証する
  • 報告されたpositionを手がかりにする
  • ソースを直して、もう一度解析する
Unexpected tokenは驚きの名前だ。テキストの出所が、本当の修正であることが多い。

解析や利用の前にJSONを検証する

NEXNARA JSON整形・検証・比較はブラウザでJSON.parseによりJSONを検証する。evalではない。

検証、2スペース・4スペース・タブでの整形、minify、コピー、ダウンロード、.jsonのアップロード。JSON Diffは入れ子のオブジェクトと配列、パス、要約、フィルタ、入れ替えに対応する。解析後、同じデータの整形版とminify版は等しいと比較される。オブジェクトのキーは名前で比較する。

5 MBより大きいテキストは遅く感じることがある。15 MBより大きいテキストはブラウザで処理しない。

JSONの検証と整形はブラウザ内で行う。このツールはJSONをNEXNARAサーバーへ送らない。広告や他のサイト機能はネットワークを使う。

失敗した文字列をJSON整形・検証・比較に貼り、引用符を書き直す前に先頭文字を読んでほしい。

FAQ

JSON.parseがUnexpected tokenと言うのはなぜ?

パーサーが止まった位置で、テキストが有効なJSONではない。典型は引用符、カンマ、余分なテキスト、HTMLなどの非JSON本体だ。

JSONのUnexpected token < は何を意味するか?

最初の不正文字が < のことがある。HTMLページを指すことが多いが、どの場合も404やHTMLの証明ではない。ステータス、Content-Type、生の本体を確認する。

JSONのエラー位置はどう見つける?

エンジンがposition、行、列を報告したら、その近くを見る。本当の誤りはより手前にあり得る。手がかりとして使い、それから検証する。

JSONは単引用符を使えるか?

いいえ。標準JSONの文字列とメンバー名は二重引用符を使う。

JSONに末尾カンマは置けるか?

いいえ。標準JSONは最後のプロパティや配列要素のあとのカンマを許さない。

文字列が有効なJSONかどうかはどう確認する?

try/catchでJSON.parseを呼ぶか、テキストをJSON整形・検証・比較に貼る。解析がSyntaxErrorを投げれば、その文字列は有効なJSONではない。

PC・モバイルのトラブル

よくあるJSONエラー:末尾カンマ、引用符、Unexpected token

無効なJSONを直す:末尾カンマ、単引用符、引用符なしのキー、Unexpected token。JSON.parseが失敗する理由と検証方法。

PC・モバイルのトラブル

スクリーンショットの JPG と PNG、どちらが小さい?

スクリーンショットは中身で JPG か PNG を選ぶ。UI と文字は PNG の方がシャープなことが多く、写真が多い画面は JPEG の方が小さくなることがある。

PC・モバイルのトラブル

画像をぼやけさせずにファイルサイズを減らす方法

見た目の品質を保ちながら、写真や画像のファイルサイズを減らします。過大なピクセルを先にリサイズし、ほどよい圧縮をかけ、合う形式を選びます。

PC・モバイルのトラブル

Unix Timestampを日付に変換:秒・ミリ秒とUTC

Unix timestampを日付へ変換する。秒とミリ秒、UTCとローカル時刻、ISO 8601、日付をepochへ戻す手順を説明する。

PC・モバイルのトラブル

なぜBase64にするとファイルが大きくなるのか

Base64はバイナリをだいたい3分の1ほど大きくします。3バイトが4文字になる構造、パディング、Data URLのオーバーヘッド、その増加が見合うときを確認します。