JavaScriptのJSON.parseで「Unexpected token」などのSyntaxErrorが出たら、まず解析対象が本当にJSON文字列かを確認してください。原因は、末尾のカンマ、シングルクォート、キーのダブルクォート不足、空文字、APIから返ったHTMLなどに分かれます。API連携ならHTTPステータス・Content-Type・本文を順に確認し、構文が正しいJSONかどうかと、データの中身がアプリの想定に合うかを切り分けましょう。
JSON.parseのUnexpected tokenは何を示す?
JSON.parseは、引数をJSONとして読み取れない場合にSyntaxErrorを投げます。文言や位置情報の表示はJavaScriptエンジン・環境によって異なり、「Unexpected token」以外の表現になることもあります。
| エラーにつながる入力例 | 主な原因 | 確認方法 |
|---|---|---|
| {'name':'A'} | シングルクォートでJSON文字列を囲む | JSONではダブルクォートが必要 |
| {name:"A"} | プロパティ名の引用符がない | "name"の形式にする |
| {"name":"A",} | 末尾のカンマ | 最後の要素の直後のカンマを外す |
| <html>…</html> | HTMLレスポンスをJSON扱い | APIのステータスと本文種類を調べる |
| 空文字列 | 解析可能なJSON値がない | レスポンス204などを区別する |
用語解説:SyntaxError
JavaScriptが規定の構文として読み取れないときに出るエラー型。JSON.parseでは受信テキストがJSON文法に合わない場合に発生します。
手順1:どの文字列をparseしているか特定する
アプリのどこでJSON.parseが呼ばれたかスタックトレースを確認し、直前に渡した値の種類をチェックします。実サービスでは入力本文をそのままログへ出すと認証情報・個人情報が混ざることがあるため注意が必要です。
function parseJsonSafely(raw) {
if (typeof raw !== "string") {
throw new TypeError("JSON用の文字列を指定してください");
}
try {
return JSON.parse(raw);
} catch (error) {
if (error instanceof SyntaxError) {
throw new Error("JSON形式の入力ではありません", {
cause: error
});
}
throw error;
}
}
この例は原因を判別する入口です。実務では、入力種別・長さ・処理の発生箇所など、機微情報を含まない情報を記録し、本文全体を無条件にログ出力しないようにします。
手順2:JSON文法を見直す
最も一般的なのは、JavaScriptオブジェクトとしては見慣れた記法をJSON文字列へ使ってしまうことです。小さな入力例で比べると違いが分かります。
// JavaScriptの文字列として正しいがJSONとしては不正
const invalid = "{'name': 'A',}";
try {
JSON.parse(invalid);
} catch (error) {
console.log(error instanceof SyntaxError); // true
}
const valid = '{"name": "A"}';
console.log(JSON.parse(valid).name); // A
JSONのプロパティ名と文字列値はダブルクォートで囲み、末尾のカンマを付けません。JavaScriptのオブジェクトリテラルとJSON文字列は同じ文法ではありません。
| 誤りの例 | 直し方 |
|---|---|
| シングルクォートの文字列 | JSON内部をダブルクォートへ |
| 末尾のカンマ | 余計なカンマを取り除く |
| undefinedやNaN | JSONとして許される値へ変換する |
| JavaScriptコメント | コメントを除去する |
| 複数のJSON値を連結 | 1つのJSONデータとして設計する |
手順3:「Unexpected token <」ならHTMLレスポンスを疑う
APIのJSONを受け取るつもりがログイン画面・404ページ・サーバーエラーのHTMLを受信していた場合、先頭にタグの記号が現れ、JSONとして解析できません。エラー文字列の「<」は一例であり、必ずこの文言になるとは限りません。
const response = await fetch("/api/users");
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
const contentType = response.headers.get("content-type") ?? "";
if (!contentType.toLowerCase().includes("json")) {
throw new Error("JSONでない応答が返りました");
}
const data = await response.json();
console.log(Array.isArray(data));
response.json()の内部でもJSONの解析が行われます。返ってきたHTTPステータスとContent-Typeを先に見ることで、APIがJSONではない応答を返した原因を調べやすくなります。Content-Typeは自己申告なので、JSONと書かれていても本文まで正しいとは限りません。
これはJSON応答を必須とするAPI向けのガード例です。Content-Typeが省略されたAPIや独自メディアタイプでは、契約に合わせて判定条件を調整してください。
手順4:204や空本文をJSON.parseへ渡さない
APIが204 No Contentを返した場合は、正常終了でも応答本文がありません。空文字に対してJSON.parseやresponse.jsonを呼ぶとSyntaxErrorになるため、本文が必要なAPIかどうかを先に判断しましょう。
async function loadItems() {
const response = await fetch("/api/items");
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
if (response.status === 204) {
return null;
}
const body = await response.text();
if (body.trim().length === 0) {
throw new Error("JSON本文が空でした");
}
return JSON.parse(body);
}
一度response.text()で読んだ本文は、同じResponseからもう一度response.json()で読むことは通常できません。どちらか一方を選んでください。この例は空本文を別のエラーへ切り分ける設計で、実際のAPI仕様に合わせてnullやエラーを選びます。
手順5:構文エラーとデータの型違いを分ける
JSON.parseでエラーが出なければ、それは「構文として正しいJSONだった」という意味です。オブジェクトのnameが文字列である、itemsが配列である、といったアプリ固有の条件まで保証しません。
const value = JSON.parse('{"items": [1, 2, 3]}');
if (
typeof value !== "object" ||
value === null ||
!Array.isArray(value.items)
) {
throw new Error("itemsが配列ではありません");
}
console.log(value.items.length);
利用するデータが外部API由来の場合は、必要に応じてスキーマバリデーションライブラリや明示的な型検査を導入し、構文チェックとデータ検証を分離します。
実務で多い原因と診断順
- コンソールのエラー位置と例外の種類を確認する。
- JSON.parseへ渡す値が文字列か、空でないか調べる。
- JSON構文(ダブルクォート・カンマ・コメント・undefined)を点検する。
- APIの場合はHTTP statusとContent-Typeを確認する。
- JSONとして解析できた後は、期待するプロパティと型を確認する。
APIが意図せずログイン画面を返した場合は、通信先URL、認証切れ、リダイレクト、プロキシ設定を調べます。CORSの制約でレスポンス自体を受け取れない場合はJSON構文以前の問題として扱ってください。
関連するJSON・非同期通信の記事
JSONの構文やデータ設計を復習したい場合は既存のJSON解説記事へ進むと理解しやすくなります。APIとfetchの基本的な動きを確認するならAjax入門も役立ちます。
(JSON文法とデータ設計については『JSON完全ガイド|基礎からAPI連携・設計原則・エラー解決まで』をご参照ください)
(APIレスポンスを受け取る手順については『JavaScriptのAjax完全入門|fetchの使い方・CORSエラーの対処・非同期通信の基本を解説』をご参照ください)
よくある質問とまとめ
JSON.parseのエラーはJavaScriptエンジンによって違いますか?
はい。エラー文言や位置表示は環境によって異なります。まずSyntaxErrorであることと渡した入力を確認しましょう。
JSON.parseで構文が正しければ型検査は不要ですか?
不要にはなりません。JSONとして有効でも、期待する構造や型と一致するかは別に確認します。
fetchは成功なのにJSON.parseで落ちるのはなぜ?
HTTP通信に成功しても、本文がHTML、空、または構文不正なJSONなら解析エラーになります。status、Content-Type、本文の形式を順に確認します。
JSON.parseのUnexpected tokenは、受信データをJSON文法として解釈できないことを知らせるエラーの一種です。入力の種類、文法、HTTPレスポンス、空本文、スキーマを分けて確認すると原因に近づけます。
まずはエラーが出た場所のJSON.parseの引数を確認し、APIの場合はステータスとContent-Typeから調べてみてください。