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 —— 安全解析模式与错误恢复