SyntaxError: Unexpected end of JSON input 表示解析器在 JSON 結構還沒完成前就讀到了字串末尾。資料被截斷。本文展示這種情況發生的所有常見方式,以及每一種該怎麼修。
這個錯誤是什麼意思
JSON.parse() 是一個狀態機。它一次一個字元地讀,追蹤打開的方括號、花括號和字串分隔符。當它走到輸入末尾,但仍「在某個東西裡面」 —— 物件、陣列或字串 —— 它就會拋:
SyntaxError: Unexpected end of JSON input這個錯誤沒有行號、沒有位置,因為問題本身就是內容缺失 —— 沒有東西可以指。
原因 1 —— API 回應被截斷
這是真實世界中最常見的原因。伺服器發了一個大型 JSON body,要麼網路提早斷線、要麼回應還沒讀完就被讀了、要麼代理或 CDN 的緩衝限制被觸發。
// 實際收到的(回應到一半連線斷了):
'{"users":[{"id":1,"name":"Ada"},{"id":2,"na'
JSON.parse('{"users":[{"id":1,...') // SyntaxError: Unexpected end of JSON input修復: 檢查 HTTP 狀態碼和 Content-Length 標頭。解析前先把原始回應的長度寫入 日誌。如果用 fetch,總是 await response.json(),而不是先讀 response.text() 再自己解析 —— 瀏覽器內建的 JSON 解析器對截斷會給出更清晰的錯誤。
// 正確
const data = await response.json();
// 脆弱 —— 把截斷錯誤藏起來
const text = await response.text();
const data = JSON.parse(text);原因 2 —— 物件或陣列沒閉合
JSON 是手寫的,或由程式碼生成時少寫了一個收尾的方括號或花括號。
JSON.parse('{"name":"Ada","plan":"pro"')
// 少了收尾的 }
// SyntaxError: Unexpected end of JSON input
JSON.parse('[1, 2, 3')
// 少了收尾的 ]
// SyntaxError: Unexpected end of JSON input修復: 用 JSON linter,或把字串貼到 JSON Fix —— 它會找出沒閉合的那個分隔符,並且在寬鬆模式下能自動補上缺的括號。
原因 3 —— 字串沒閉合
一個字串值沒用收尾的雙引號結束,常見是因為字串內部帶了一個未跳脫的雙引號:
JSON.parse('{"title":"He said "hello" to her"}')
// ^ 未跳脫的引號提前結束了字串
// SyntaxError: Unexpected end of JSON input
// 正確 —— 內部引號用反斜線跳脫:
JSON.parse('{"title":"He said \"hello\" to her"}')修復: 把內部雙引號跳脫成 \",或一開始就用 JSON.stringify() 來建立 JSON,而非手工拼字串。
原因 4 —— 空字串
把空字串或只有空白的字串傳給 JSON.parse() 也會拋同樣的錯 —— 根本沒有輸入可解析。
JSON.parse('') // SyntaxError: Unexpected end of JSON input
JSON.parse(' ') // SyntaxError: Unexpected end of JSON input
JSON.parse() // SyntaxError: Unexpected token u…(undefined 被轉成字串)這經常發生在表單欄位、localStorage 的 key、或環境變數為空的時候。
// 解析前先 guard
const raw = localStorage.getItem('session');
if (!raw) return null;
return JSON.parse(raw);原因 5 —— 串流回應讀得太早
在消費串流 API 或 WebSocket 時,很容易在整條訊息還沒到齊之前就先去解析一個 chunk。
// ❌ 試圖解析不完整的 chunk
ws.onmessage = (event) => {
const data = JSON.parse(event.data); // 可能不完整
};
// ✓ 緩衝到訊息邊界(應用層分幀)
let buffer = '';
ws.onmessage = (event) => {
buffer += event.data;
if (buffer.endsWith('\n')) { // 或檢查已知的分隔符
const data = JSON.parse(buffer.trim());
buffer = '';
}
};診斷截斷:Content-Length 與串流讀取器
兩個具體技巧,用來確認回應是否真的被截短:
- 對比
Content-Length。 如果伺服器有設,可以直接偵測到短讀:const res = await fetch(url); const expected = Number(res.headers.get('Content-Length') ?? NaN); const text = await res.text(); if (Number.isFinite(expected) && text.length !== expected) { throw new Error(`truncated: got ${text.length} of ${expected} bytes`); }注意:
Content-Length在分塊或壓縮回應中可能不存在。 - 用串流 body 讀取器讀。 用
res.body.getReader()可以讓你逐塊觀察資料到達,並察覺串流在 payload 中間關閉 —— 這就是連線中斷或代理逾時的徵兆。如果串流被中止,瀏覽器會以fetchrejection 形式暴露底層網路失敗;配合解析器錯誤一起看會更準確。
快速 診斷清單
- 在呼叫 parse 之前,記錄
typeof input與input.length。 - 如果長度看起來太短,回應被截斷了 —— 看網路日誌。
- 如果長度是 0,來源(API、儲存、環境變數)什麼都沒回 —— 加 guard。
- 如果長度看起來對,把字串貼到 JSON Fix 找結構問題。
在正式環境優雅地兜底
function safeParse(text, fallback = null) {
if (!text || !text.trim()) return fallback;
try {
return JSON.parse(text);
} catch {
console.error('JSON parse failed, input length:', text.length);
return fallback;
}
}常見問題
「Unexpected end of JSON input」由什麼引起?
解析器在仍處於物件、陣列或字串內部時走到字串末尾 —— 資料不完整。最常見的真實原因是 API 回應被截斷;其他情況包含未閉合的括號、未結束的字串、空字串。
為什麼沒有行號或位置?
因為問題是內容缺失,而不是某個字元錯了。解析器沒有東西可指 —— 它只是在結構閉合之前把輸入用完了。
空字串的情況怎麼修?
解析前加 guard:if (!raw || !raw.trim()) return fallback;。空表單欄位、localStorage 中缺失的 key、未設定的環境變數是最常見來源。
在正式環境怎麼優雅處理?
用一個 safeParse 輔助函式把 JSON.parse() 包起來,失敗時回傳一個 fallback(見上方片段),並把輸入長度寫入日誌,便於區分截斷與結構問題。完整的模式集請見 在 JavaScript 中處理壞掉的 JSON。
在瀏覽器中修復被截斷的 JSON
有一段壞掉的 JSON 字串需要檢查或修復?JSON Fix 在 fixjson.org 上解析、驗證 並自動修復常見結構錯誤 —— 包括缺失的括號 —— 全部在瀏覽器中完成,沒有資料被送往任何伺服器。
- JSON Fix —— 修復並格式化不合法的 JSON
- 修復「[object Object] is not valid JSON」 —— JSON 語法錯誤完整指南
- Unexpected Token 錯誤解析 —— token 層級解析錯誤的搭檔指南
- 在 JavaScript 中處理壞掉的 JSON —— 捕獲並還原各種解析錯誤的模式