"Unexpected end of JSON input" の直し方
JSON.parse や res.json() でSyntaxError: Unexpected end of JSON input が出るのは、JSONとして完結する前に入力が終わったときです。実際の原因はほぼ 「空文字列」「空レスポンス」「途中で切れたJSON」の3つに絞れます。
This guide explains why JSON.parse throws "Unexpected end of JSON input" and walks through the three real-world causes: empty strings, empty response bodies, and truncated JSON.
TL;DR
- 最頻出は
JSON.parse("")。localStorage の未保存キーや空のAPIボディが典型 - fetch なら 204 No Content・エラー時の空ボディを疑う。
res.json()の前にステータス確認 - ログや文字列連結で JSONが途中で切れていないかはJSON整形ツールに貼ると一瞬で分かる
JSONエラーを診断
JSON文字列またはエラーメッセージから、よくある原因と修正方法を推測します。
1. エラーの意味 / What the error means
パーサーは { や [ を読み始めると、対応する閉じ記号まで読み切ろうとします。 その途中で入力が尽きると「end of input(入力の終端)に予期せず到達した」としてこのエラーになります。 つまり壊れた文字があるのではなく、続きが無いのが特徴です (壊れた文字がある場合は Unexpected token エラーになります)。
The parser reached the end of the string while a JSON value was still open. Nothing is malformed — the rest of the document is simply missing.
2. 原因別の対処 / Causes and fixes
| 状況 / Situation | 原因 / Cause | 対処 / Fix |
|---|---|---|
JSON.parse(localStorage.getItem(...)) | 値が ""(空文字列) / Empty string | v ? JSON.parse(v) : null でガード |
res.json() が reject する | 204/205 や DELETE 成功時の空ボディ / Empty body | ステータスで分岐してから parse |
| エラー時だけ落ちる | サーバーが 500 で空ボディを返す / Empty error body | res.ok を先に確認 |
| ログから拾ったJSONで発生 | 出力が文字数制限で切れた / Truncated log | 元データを再取得(ログは信用しない) |
| 大きなファイルの読み込みで発生 | 書き込み未完了・転送中断 / Incomplete write | 生成側で flush/close を確認 |
| ストリーミング受信で発生 | チャンク単位で逐次 parse している / Parsing partial chunks | 全チャンク連結後に parse(または NDJSON 化) |
3. fetch の安全な書き方 / Safe fetch pattern
const res = await fetch(url);
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
// 204 や空ボディでも落ちない
const text = await res.text();
const data = text ? JSON.parse(text) : null;res.json() を直接呼ばず一度 text() で受けてから判定するのが 最も堅牢です。ステータスコードの意味はHTTPステータスコード検索で確認できます。
4. ブラウザ・環境ごとの文言差 / Error wording by environment
- Chrome / Node.js:
Unexpected end of JSON input - Firefox:
JSON.parse: unexpected end of data at line 1 column 1 - Safari:
JSON Parse error: Unexpected EOF
文言は違っても原因と対処は同じです。検索するときはこのページの3原因(空文字列・空ボディ・途中切れ)を順に当てはめてください。
4.5 このサイトの自動診断ツールでの見分け方 / How our error diagnoser tells these apart
この記事の上部にも埋め込まれている JsonErrorDiagnoser は、入力されたエラーメッセージ文字列から unexpected end や end of data などのキーワードを正規表現で検出します。その場合は「Unexpected token」系とは分けて、空レスポンス、HTTPステータスの確認漏れ、JSONの途中切れを原因候補として提示する設計です。
単なるキーワード一致だけでなく、エラーメッセージ内の position N や line N column N という表記から位置情報も抽出し、入力のどこで問題が起きたかを示そうとします。
The embedded JsonErrorDiagnoser uses regular expressions to recognize messages such as unexpected end and end of data, then suggests empty responses, unchecked HTTP status codes, or truncated JSON rather than the usual “Unexpected token” causes. It also attempts to extract location details from position N and line N column N forms.
5. パターン別の再現コードと実際のエラー文言 / Minimal repros with actual error text
以下は Node.js v24 で実際に実行して確認したエラー文言です(ブラウザの Chrome も V8 エンジンのため同じ文言になります)。
(a) 空文字列を JSON.parse する
JSON.parse("");
// SyntaxError: Unexpected end of JSON input(b) fetch の res.json() を2回呼ぶ(body used)
レスポンスボディは一度しか読めないストリームです。text() や json() を呼んだ後にもう一度呼ぶと、 実は Unexpected end of JSON input ではなく別のエラーになります。
const res = await fetch(url);
await res.json();
await res.json();
// TypeError: Body is unusable: Body has already been read「JSONのエラーだと思ったら実は2回読みだった」というケースは意外と多いので、まず呼び出し回数を確認してください。
(c) 204 No Content を res.json() する
const res = new Response(null, { status: 204 });
await res.json();
// SyntaxError: Unexpected end of JSON inputボディが空のため JSON.parse と同じ文言になります。ステータス確認なしに res.json() を呼ぶ実装で起きがちです。
(d) 途中で切断されたレスポンス
切れる位置によって文言が変わります。コロンや配列の要素区切りの直後で切れると Unexpected end of JSON input になりますが、それ以外の位置で切れると別の文言(Expected ... in JSON at position N)になります。
JSON.parse('{"a":');
// SyntaxError: Unexpected end of JSON input
JSON.parse('[1,2,');
// SyntaxError: Unexpected end of JSON input
JSON.parse('{"a":1');
// SyntaxError: Expected ',' or '}' after property value in JSON at position 6
JSON.parse('{');
// SyntaxError: Expected property name or '}' in JSON at position 1つまり「途中で切れた」からといって必ずこのエラー文言になるとは限りません。検索でここに辿り着いた場合は、position N のエラーもあわせて「JSONが途中で切れている」系のトラブルとして扱ってください。
(e) localStorage に文字列 "undefined" が保存されていた場合
localStorage.setItem(key, value) に undefined を渡すと、 文字列 "undefined" として保存されてしまいます。これを JSON.parse すると、 Unexpected end of JSON input ではなく別の文言が出ます。
JSON.parse("undefined");
// SyntaxError: "undefined" is not valid JSONこちらもよく混同されるケースです。JSON.parse(localStorage.getItem(key)) が失敗する場合は、 値が空文字列なのか文字列 "undefined" なのかをまず console.log で確認してください。
6. ブラウザ別エラーメッセージ対照表 / Error wording by browser
| 環境 / Environment | JSONの値が無い場合の文言 |
|---|---|
| Chrome / Node.js(V8) | SyntaxError: Unexpected end of JSON input |
| Firefox(SpiderMonkey) | SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data |
| Safari(JavaScriptCore) | SyntaxError: JSON Parse error: Unexpected EOF |
いずれも「入力が途中で終わった」ことを意味する点は共通です。エンジンごとの文言差はJSON整形ツールで貼り付けて検証すれば意識しなくても済みます。
7. 防御パターンの使い分け / Defensive parsing patterns
単に try-catch で握りつぶすと、次に同じ問題が起きたときの調査が難しくなります。 原因の切り分けがしやすい実装は次の形です。
async function safeParseResponse(res) {
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const text = await res.text();
if (text.length === 0) {
return null;
}
try {
return JSON.parse(text);
} catch (e) {
console.error("JSON parse failed. head:", text.slice(0, 200));
throw e;
}
}ポイントは3つです。(1) res.ok と status を先に見る、(2) text() で受けて長さを確認してから JSON.parse する、(3) catch した例外を握りつぶさず、元の文字列の先頭だけでもログに残す。 文字列全体をログに出すと機密情報を含む場合があるため、slice(0, 200) のように先頭のみに留めるのが安全です。
8. English summary
JSON.parse throws "Unexpected end of JSON input" when the input ends while a JSON value is still open. In practice the cause is almost always one of three things: parsing an empty string (e.g. a missing localStorage key), calling response.json() on an empty body (204 No Content, DELETE responses, or error responses with no payload), or JSON that was truncated by a log line limit or an incomplete file write. Guard withconst text = await res.text(); const data = text ? JSON.parse(text) : null; and checkres.ok before parsing. Firefox reports the same problem as "unexpected end of data" and Safari as "Unexpected EOF".
よくある質問 / FAQ
- JSON.parse("") はなぜこのエラーになる?
- 空文字列は「JSONの値が始まる前に入力が終わった」状態のため、Unexpected end of JSON input になります。値が無い可能性があるなら text ? JSON.parse(text) : null のようにガードします。
- 204 No Content のレスポンスで res.json() を呼ぶとどうなる?
- ボディが空のため Unexpected end of JSON input で reject されます。ステータスが 204 や 205 の場合は res.json() を呼ばない分岐を入れます。
- Why does an empty fetch response throw this error?
- response.json() internally runs JSON.parse on the body text. An empty body means the parser reaches the end of input before finding a JSON value, so it throws. Read response.text() first and parse only when it is non-empty.
関連ツール / Related tools
- JSON Formatter & Validator - 貼り付けるだけで切れている位置を特定
- HTTP Status Code 検索
- JSON Schema Validator