SyntaxError: Unexpected token o in JSON at position 1 —— 那個小寫的 o 是 [object Object] 的第二個字元。它代表你把一個 JavaScript 物件直接傳給了 JSON.parse(),而不是一個 JSON 字串。本文說明這個錯誤的每一種變體,以及如何在一分鐘內修復每一種情況。
為什麼錯誤訊息會說 "token o"
當你把一個非字串值傳給 JSON.parse() 時,JavaScript 會先將它強制轉換為字串。普通物件會被轉換成 "[object Object]"。解析器先看到位置 0 的 [(合法 —— 表示陣列開始),然後是位置 1 的 o(非法 —— 不是合法的陣列元素)。所以會報:Unexpected token o at position 1。
JSON.parse({})
// 等同於: JSON.parse("[object Object]")
// SyntaxError: Unexpected token o in JSON at position 1最常見的原因:沒有 await response.json()
這是實際程式碼庫中這個錯誤的頭號來源。fetch() 回傳的 Response 物件不是字串 —— 它是一個 ReadableStream 的包裝。把它傳給 JSON.parse() 會被強制轉換為 "[object Response]"。
// ❌ 錯誤 —— response 是 Response 物件,不是字串
const response = await fetch('/api/user');
const data = JSON.parse(response);
// SyntaxError: Unexpected token o in JSON at position 1
// ✓ 正確 —— 讓瀏覽器把資料流解析為 JSON
const data = await response.json();同樣地,如果你呼叫 response.text() 但沒有 await,得到的會是一個 Promise 物件(會被強制轉換為 "[object Promise]")。
// ❌ 漏寫了 await —— text 是 Promise,不是字串
const text = response.text();
const data = JSON.parse(text);
// SyntaxError: Unexpected token o in JSON at position 1
// ✓ 正確
const text = await response.text();
const data = JSON.parse(text);其他會觸發同樣錯誤的物件
| 你傳入的內容 | JS 將其強制轉換為 | 錯誤 token |
|---|---|---|
{} 或任何普通物件 | "[object Object]" | token o 位於位置 1 |
undefined | "undefined" | token u 位於位置 0 |
true / false | "true" / "false" —— 實際上是合法的 JSON! | 無錯誤 |
一個 Response 物件 | "[object Response]" | token o 位於位置 1 |
一個 Promise | "[object Promise]" | token o 位於位置 1 |
null | "null" —— 合法 JSON | 無錯誤(回傳 null) |
原因:傳入物件而不是先序列化
一個相關的錯誤:嘗試"解析"你記憶體中已經擁有的 JavaScript 物件。JSON.parse() 接受的是字串;如果你已經有了物件,根本不需要去解析它。
const config = { host: 'localhost', port: 3000 };
// ❌ 毫無意義 —— config 已經是物件
const parsed = JSON.parse(config);
// ✓ 如果想深拷貝,使用 structuredClone 或 stringify + parse
const clone = JSON.parse(JSON.stringify(config));
// ✓ 如果想傳送出去,使用 JSON.stringify
const body = JSON.stringify(config);原因:Python 或其他後端回傳了錯誤的 Content-Type
有時伺服器回傳的是純文字錯誤訊息(像是 "ok" 或 "not found"),狀態碼是 200 而且沒有 Content-Type 標頭。前端預設是 JSON,呼叫 response.json(),於是因為回應內容不是合法 JSON 而拋出 unexpected token 錯誤。
// 伺服器送出的字串字面值: ok
// 瀏覽器嘗試當作 JSON 解析:
JSON.parse("ok")
// SyntaxError: Unexpected token o in JSON at position 0修復方法:在呼叫 response.json() 之前,先檢查 response.ok 和 response.headers.get('Content-Type'):
const response = await fetch('/api/action');
if (!response.ok) {
const text = await response.text(); // 安全 —— 可能不是 JSON
throw new Error(`HTTP ${response.status}: ${text}`);
}
const data = await response.json();不太常見的 [object X] 變體
任何 toString() 回傳以 [object 開頭字串的值,都會在位置 1 觸發同樣的錯誤。除了 [object Object] 以外,實際程式碼中真正會遇到的有:
[object Module]—— 傳入動態匯入的結果:const mod = await import('./data.json', { with: { type: 'json' } });你想要的是mod.default,而不是mod。[object AsyncFunction]—— 傳入了非同步函式參考,而不是呼叫它:應序列化fn()(Promise 的兌現值),而不是fn。[object HTMLDocument]—— 誤傳了document(例如從除錯器殘留程式碼片段中)。[object FormData]—— 使用fetch(url, { body: formData })沒問題,但JSON.parse(formData)不行 —— 請先用Object.fromEntries(formData)轉換。
快速修復清單
- fetch + JSON.parse? 替換為
await response.json()。 - 呼叫鏈上某處漏了 await? 解析之前的每一次
async呼叫都必須 await。 - 已經是物件了? 不需要解析 —— 直接使用,或用
structuredClone()複製。 - 伺服器出錯時回傳非 JSON? 用
response.text()讀取,而不是response.json(),尤其當回應可能不是 JSON 時。
常見問題
"Unexpected token o in JSON at position 1" 是什麼意思?
你把一個 JavaScript 物件傳給了 JSON.parse()。JavaScript 把物件強制轉換為字串 "[object Object]";解析器接受位置 0 的 [,但拒絕位置 1 的 o。
使用 fetch 時要如何修復?
不要呼叫 JSON.parse(response)。改用 await response.json(),它會讀取回應資料流並替你解析。確認呼叫鏈中的每一步都有 await。
已經有物件了還需要 JSON.parse 嗎?
不需要。JSON.parse() 只把一個 JSON 字串 轉成值。如果你已經持有物件,直接使用就好,或用 structuredClone() 進行深拷貝,而不要用 JSON.parse(JSON.stringify(obj))。
"Unexpected token o" 和 "[object Object] is not valid JSON" 是同一個錯誤嗎?
根本原因相同 —— 物件在解析前被字串化了。較新的 V8 版本會印出 [object Object] is not valid JSON 的措辭;較舊的版本則印出 Unexpected token o。完整說明請見 修復 "[object Object] is not valid JSON"。
檢查原始回應
如果不確定 API 實際回傳的內容,把回應內容貼到 JSON Fix 進行驗證。如果不是合法 JSON,驗證工具會明確告訴你哪裡有問題。
- JSON Fix —— 在瀏覽器中驗證與修復 JSON
- 修復 "[object Object] is not valid JSON" —— JSON 語法錯誤的完整指南
- Unexpected end of JSON input —— 當解析器在結構完成前耗盡輸入
- 在 JavaScript 中處理損壞的 JSON —— 安全解析模式與錯誤復原