跳到主要內容

← 返回部落格

常見的 JSON 錯誤與修正方法

幾乎每個「Unexpected token in JSON」錯誤,都來自同一份很短的失誤清單。以下逐一列出與修法。(不熟這格式?先看 JSON 是什麼。)

這些是我們工具實際印出來的訊息。 我們把六段壞掉的 JSON 餵進 JSON 格式化工具,把回來的字一字不改記下來,方便你比對眼前那句:

  • {"a":1,} → Expected double-quoted property name in JSON at position 7 (line 1 column 8)
  • {'a':1} 與 {a:1} → Expected property name or ’}’ in JSON at position 1 (line 1 column 2)
  • {"a":{"b":1} → Expected ’,’ or ’}’ after property value in JSON at position 12 (line 1 column 13)
  • {"a":undefined} → Unexpected token ‘u’, ”{“a”:undefined}” is not valid JSON
  • {"a":1 "b":2} → Expected ’,’ or ’}’ after property value in JSON at position 7

兩件值得知道的事:單引號字串與沒加引號的鍵會產生完全相同的訊息,因為剖析器兩種情況都在同一個位置放棄。另外訊息的字句來自瀏覽器自己的 JSON 剖析器,所以 Firefox 與 Safari 的講法不一樣 —— 可以依賴的是那個位置數字。行列標註是我們的工具自己加上去的。

1. 多餘的逗號

JSON 不允許最後一項後面還有逗號:

{ "a": 1, "b": 2, }   ← 無效
{ "a": 1, "b": 2 }    ← 有效

2. 單引號

字串與屬性名必須用雙引號:

{ 'name': 'Ann' }   ← 無效
{ "name": "Ann" }   ← 有效

3. 屬性名沒加引號

不像 JavaScript 物件,JSON 的鍵一定要加引號:

{ name: "Ann" }     ← 無效
{ "name": "Ann" }   ← 有效

4. 註解

JSON 不能有註解。解析前把 // 與 /* */ 移除。

5. 括號錯誤或缺漏

每個 { 都要有 }、每個 [ 都要有 ]。常見的是括號混用,或忘了把多筆資料用陣列 [ … ] 包起來。

少一個括號,是所有錯誤裡「回報位置離錯誤最遠」的那一個。{"a":{"b":1} —— 少一個右大括號 —— 給的是

✗ JSON syntax error: Expected ',' or '}' after property value in JSON at position 12 (line 1 column 13) [L1:13]

位置 12 是輸入的結尾,因為解析器要一直讀到沒有字元可讀,才知道少了東西。錯誤在左邊那個開頭的 {;回報在最右邊。對照少一個逗號的 {"a":1 "b":2},它給的是

✗ JSON syntax error: Expected ',' or '}' after property value in JSON at position 7 (line 1 column 8) [L1:8]

同一句訊息,但位置 7 剛好落在逗號本來該在的地方。當回報的欄位是檔案的最後一個字元時,要去找沒關的括號,而不是去讀它指的那一行。

6. 非數值的值

NaN、Infinity、undefined 都不是合法 JSON。請改用數字、字串或 null。

「不是數字」的值又是另一種失敗方式,而訊息本身就說了。{"a":undefined} 給的是

✗ JSON syntax error: Unexpected token 'u', "{"a":undefined}" is not valid JSON

注意解析器是把你整段輸入原樣引回來,而不是給一個欄位:它連把 undefined 當成一個值來解讀都做不到,所以不存在「哪個合法 token 出錯」的位置。NaN 和 Infinity 也是同樣的失敗。JSON 表達「沒有值」只有一種寫法,就是 null。

最快的修法:驗證

與其用肉眼找,不如把 JSON 貼進會指出錯誤位置的驗證工具:

修好上面六個失誤,絕大多數「JSON 無效」的問題就會消失——全程在你的瀏覽器本機執行,連機敏資料也不外流。

實際範例:修正前後

以下這段同時踩到上面三個雷:

{
  'user': "Ann",
  "roles": ["admin", "editor",],
  "active": True,
}

解析器只會停在第一個遇到的問題,丟出類似 Unexpected token ' at position 4 的簡短訊息——即使實際上有三個錯。一次修好:把單引號換成雙引號、刪掉兩個多餘逗號、把布林值改小寫:

{
  "user": "Ann",
  "roles": ["admin", "editor"],
  "active": true
}

要特別小心 True、False、None——那是 Python 的寫法。JSON 只認得小寫的 true、false 與 null。

JSON 不是 JavaScript 物件

多數錯誤都源自「把 JSON 當成 JavaScript 原始碼」。其實不是——JSON 是一種語法更嚴格的文字格式:

  • 鍵一律是加引號的字串,不能是裸識別字;
  • 只接受直的雙引號,不接受單引號、反引號,也不接受文書軟體自動換成的彎引號;
  • 不能有多餘逗號、註解或函式呼叫;
  • 數字不能以正號或前導零開頭,結尾也不能只有一個點。

只要有辦法,就用真正的序列化器產生 JSON——JavaScript 用 JSON.stringify、Python 用 json.dumps——別自己手動拼字串,它每次都會把引號與跳脫處理正確。

常見問答

為什麼錯誤說「position 0」?

輸入是空的、開頭有位元組順序記號(BOM),或那其實是一頁 HTML 錯誤頁而不是 JSON。先確認 API 到底回了什麼,再怪語法。

設定檔可以留註解嗎?

純 JSON 不行。編輯時可用 JSON5 或 JSONC,或改用 YAML,送進嚴格解析器前再把非標準的部分清掉。

檔案太大打不開怎麼辦?

先格式化,讓層次顯現,再把不需要的分支收合起來。貼進 JSON 格式化工具 一步就能同時做到。