跳至內容

常見 JSON 語法錯誤與修正方法

整理實務上最常遇到的八種 JSON 語法錯誤——結尾逗號、單引號、BOM、NDJSON——並提供具體修正方式。

SyntaxError: Unexpected token } in JSON at position 47 大概是現代開發 裡最沒幫助的錯誤訊息。解析器告訴你它在哪裡放棄,而不是哪裡出了錯。 本文整理八種佔據幾乎所有「JSON 壞了」工單的語法錯誤,並逐一說明如何 修正。

為何「Unexpected token」訊息沒幫助

大多數 JSON 解析器是狀態機,遇到第一個非預期的位元組就中止。它回報的 位置 是解析器發現不對勁的地方,通常已經是真正錯誤的下游。第 3 行 的缺逗號,會以「unexpected token」出現在第 4 或第 5 行。

兩個習慣有幫助:

  • 永遠驗證整份文件。不要修一行就重跑;先修完再驗證,因為下個錯誤 常常要等前一個錯誤修掉才會浮現。
  • 當錯誤位置已超過檔案結尾(4710 個字元的檔案卻說 position 4711), 代表文件被截斷——把注意力放在未閉合的括號與引號上。

JSON 驗證工具 會針對每種錯誤類別給出 可讀的原因說明。

1. 結尾逗號

最常見的錯誤。JavaScript 允許結尾逗號,JSON 不允許。

{
  "a": 1,
  "b": 2,
}

修正——把閉合括號前那個逗號移除:

{
  "a": 1,
  "b": 2
}

陣列也適用:[1, 2, 3,] 同樣不合法。

2. 缺少或多餘的逗號

物件或陣列中,每個值與下一個值之間必須恰好一個逗號:

{
  "a": 1
  "b": 2
}

修正——在 1 之後補上逗號。鏡像版本是 {"a": 1,, "b": 2},多了一個。

3. 單引號與未加引號的鍵

JavaScript 物件字面值很寬容;JSON 不寬容。所有字串(包括物件鍵) 都必須使用雙引號。

不合法:

{ name: 'Ada', role: "admin" }

合法:

{ "name": "Ada", "role": "admin" }

如果你是從 console 或 stack trace 貼 JS 物件,這幾乎一定是第一個壞掉 的地方。JSON 修復工具 會自動為你加引號、把單 引號改成雙引號。

4. JSON 內的註解

JSON 沒有註解。///* */# 全部是語法錯誤。

{
  // user record
  "id": 42
}

修正——把註解移除,或移到 JSON 外部(旁邊的檔案、外層 schema,或者 真的非要的話,用 _comment 鍵內嵌)。VS Code 用於 tsconfig.json 的 JSONC 允許註解,但它不是 JSON,大多解析器會拒絕。

5. 字串中未跳脫的字元

JSON 字串內以下字元 必須 跳脫:

  • "\"
  • \\\
  • 控制字元(U+0000 至 U+001F)——例如字面上的換行必須寫成 \n, tab 寫成 \t

常見錯誤——直接貼上字面換行進字串:

{ "message": "line one
line two" }

修正:

{ "message": "line one\nline two" }

斜線 / 可以選擇性跳脫為 \/,但不是必要。

6. BOM 與編碼問題

UTF-8 的 BOM 是三個位元組 EF BB BF,某些編輯器會寫在檔頭。JSON 規格 禁止檔頭出現 BOM。嚴格解析器(Node 的 JSON.parse、Go 的 encoding/json、部分設定下的 Python json)會以「unexpected token at position 0」拒絕。

症狀——檔案在編輯器看起來沒問題,但用 hex viewer 會發現開頭 { 之前 有非列印字元。

修正——重新存成「UTF-8 無 BOM」。多數編輯器在編碼選單中有這個選項。 命令列:

sed -i '1s/^\xEF\xBB\xBF//' broken.json

7. JSONP 與 Python 字面值輸出

兩種常被誤認為 JSON 的非 JSON 格式:

  • JSONP——callback({"a":1});。這是把 JSON 形狀當引數的 JS 函式呼叫。把外層的 callback 與結尾分號去掉就會得到 JSON。
  • Python repr 輸出——{'a': 1, 'b': True, 'c': None}。單引號、大寫 True/False/None。在 Python 中要產生真正的 JSON,用 json.dumps 而非 print

JSON 修復工具 兩者都能處理。

8. 截斷或串接的 JSON / NDJSON

兩種失敗模式:

  • 截斷——檔案在文件中途被切斷。解析器會在輸入結尾失敗,因為括號未閉合。把實際檔案大小與預期對比,必要時重新下載。
  • 串接——兩份合法 JSON 文件首尾相連:{"a":1}{"b":2}。若中間有換行,這是NDJSON(或 JSON Lines),是日誌串流的常見格式。請逐行解析,而非當成單一文件:
for (const line of text.split("\n")) {
  if (!line.trim()) continue;
  const record = JSON.parse(line);
  // ...
}

快速找出並修正

排錯流程:

  1. 把文件丟進 JSON 驗證工具——它會回報第一個錯誤與最可能的原因。
  2. 若是結構性錯誤(結尾逗號、單引號、未加引號的鍵、BOM),用 JSON 修復工具 一次正規化。
  3. 兩個都試過還是錯,那這份文件大概是被截斷,或根本不是 JSON(HTML 錯誤頁、Python repr、JSONP)。檢視開頭與結尾各 100 個位元組通常就會發現。

延伸閱讀