FormatArc 简体中文版 JSON 格式化工具的转换结果界面FormatArc 简体中文版 JSON 格式化工具的转换结果界面
作者: FormatArc 编辑部发布日期: 2026-09-02更新日期: 2026-09-02

JSON parse 报错排查:Unexpected token 原因与修复方法

处理 JSON 的时候,几乎都会遇到 SyntaxError: Unexpected token 这个报错。正在调 API 响应、读取配置文件、处理导出的文件,突然一行报错蹦出来,工作就卡住了。

报错位置不好找的话,直接把内容粘贴到 JSON 格式化工具,它会告诉你具体哪一行、哪个字符出了问题。

知道了原因,修复本身不难。但光看报错信息,很多时候判断不了到底是什么问题。这篇文章讲怎么读 JSON parse 报错,以及最常见的 5 类原因,每个都配了具体示例。

怎么读 SyntaxError: Unexpected token

在浏览器或 Node.js 里解析 JSON,遇到语法问题会返回这样的错误:

SyntaxError: Unexpected token ' in JSON at position 42

这条信息包含三个部分:

  • Unexpected token ' — 解析器遇到了一个它不认识的字符,这里是 '(单引号)
  • at position 42 — 错误出现在 JSON 字符串从第 1 个字符起算的第 42 个字符处
  • SyntaxError — 语法本身有问题(不是数据内容的问题,是写法的问题)

position 指的是字符位置,不是字节位置。换行符和空格也算在里面,所以在大文件里手动数位置很不现实。用 JSON 格式化工具 一类的工具可以立刻定位到出错的位置。

常见 5 大原因

1. 尾逗号(trailing comma)

JavaScript 里数组和对象末尾可以加逗号,但 JSON 规范不允许尾逗号。

{
  "name": "Alice",
  "age": 30,
}

最后一个 30, 的逗号要去掉:

{
  "name": "Alice",
  "age": 30
}

如果你的编辑器格式化工具会自动在末尾加逗号,建议在 JSON 文件上关掉这个选项。

2. 单引号

Python 字典和 JavaScript 对象里可以用 ',但 JSON 只认双引号 "

{'name': 'Alice'}

这不是合法的 JSON,需要全部换成双引号:

{"name": "Alice"}

在 Python 里把字典变成 JSON 字符串时,用 json.dumps() 而不是 str()str() 会输出单引号。

3. 键没加引号

JavaScript 对象里键可以不加引号,JSON 要求所有键必须用双引号包起来。

{name: "Alice"}

正确写法:

{"name": "Alice"}

4. 注释

配置文件里经常犯的错误。JSON 规范没有注释语法。

{
  // 用户姓名
  "name": "Alice"
}

///* */ 都要去掉。tsconfig.json 这类文件用的是 JSONC(JSON with Comments)扩展格式,允许注释,但标准 JSON 解析器不认。JSONC、JSON5、_comment 字段、移除脚本各自的取舍,见 JSON 可以注释吗?

如果配置文件确实需要保留注释,可以考虑用 YAML。YAML 原生支持 # 注释,两个格式之间可以用 YAML JSON 转换工具 互相转。

5. BOM(字节顺序标记)

UTF-8 文件开头如果带有 BOM(\uFEFF),解析器会把它当作非法字符。

SyntaxError: Unexpected token  in JSON at position 0

报错位置是 0、又看不到可疑字符的时候,大概率是 BOM。在编辑器里重新保存为无 BOM 的 UTF-8,或者在代码里去掉再解析:

const cleaned = text.replace(/^\uFEFF/, '');
const data = JSON.parse(cleaned);

其他原因

除了上面 5 个,下面这些也会导致解析报错。

括号不匹配

少了一个 }],通常会在文件末尾报错。嵌套层次多的 JSON,肉眼很难找到哪个括号没配对。用支持括号高亮的格式化工具能省很多时间。

字符串里的控制字符

字符串里混入了未转义的换行符或制表符会直接报错。换行需要写成 \n

{"message": "Hello
World"}

正确写法:

{"message": "Hello\nWorld"}

前导零的数字

JSON 数字不允许前导零。007 是非法值,要改成 7

undefined 和 NaN

JavaScript 的 undefinedNaN 不能当 JSON 值用。包含 undefined 的对象做序列化时,大多数序列化库会跳过该键或直接报错。Infinity 同样会被拒绝。

GBK 编码:中文环境下的高频陷阱

上面 5 个原因之外,GBK 编码是中文开发者会额外遇到的一个坑。

Windows 下不少程序——记事本、Excel、旧版日志工具——保存文本文件时默认用 GBK 而不是 UTF-8。如果你的 JSON 文件用 GBK 编码保存,然后被 UTF-8 解码器读取,中文字符会变成乱码,解析器直接报错。

举个例子,汉字"名"在 GBK 里是 2 个字节:0xC3 0xC7。UTF-8 解码器看到 0xC3,会认为这是一个 2 字节 UTF-8 字符的开头,期待第二个字节在 0x800xBF 范围内。0xC7 不在范围内,解码直接失败。

Python 里最典型的报错:

import json

with open("config.json", encoding="utf-8") as f:
    data = json.load(f)

如果 config.json 是 GBK 编码的,open() 这一步就会抛出:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 3: invalid continuation byte

注意,报错发生在 open() 读取阶段,还没到 json.loads()

解决方法是显式指定编码:

with open("config.json", encoding="gbk") as f:
    data = json.load(f)

如果不确定文件是什么编码,也可以先用 iconv 转成 UTF-8 再解析(Linux 自带 iconv;macOS 通过 Homebrew 安装;Windows 需额外安装):

iconv -f GBK -t UTF-8 config.json > config_utf8.json

Node.js 里情况类似,fs.readFileSync('config.json', 'utf-8') 默认按 UTF-8 解码。GBK 文件同样会乱码,需要用 iconv-lite 之类的库先转码。

两个补充说明:

  • 纯 ASCII 的 JSON(只有英文字母、数字、标点)在 GBK 和 UTF-8 下字节完全一样,不会出现这个问题。但只要包含中文字符,GBK 文件在 UTF-8 解码器下就会出错。
  • 有些 Windows 程序保存的是"带 BOM 的 UTF-8",开头的 EF BB BF 三个字节会导致 Unexpected token 报错。这和 GBK 是不同的问题,但症状看起来很像,排查时两个都要检查。

按症状找原因:token u / token o / end of input

报错信息里提到的那个字符,往往能直接帮你缩小范围。下面 3 个变体都不是 JSON 文件内容的问题,而是"传给解析器之前"就出了问题。另外,如果看到的是 Unexpected token <,说明返回的不是 JSON 而是 HTML(参见后文环境差异表)。

Unexpected token u in JSON at position 0

JSON.parse 收到了字符串 "undefined"u 是这个字符串的第一个字符。这几乎可以确定是你要解析的值在那个时候就是 undefined

const raw = localStorage.getItem("settings"); // 键不存在时返回 null
JSON.parse(undefined); // 报错: "undefined" is not valid JSON

解析之前先确认值是否存在。API 响应体为空、存储键不存在、变量名拼错,是最常见的三个原因。

Unexpected token o in JSON at position 1

解析器收到了 "[object Object]" 这个字符串。position 0 的 [ 看起来像数组开头,所以旧版引擎报告在 position 1 的 o 处失败。把 JavaScript 对象直接传给 JSON.parse 时,隐式字符串转换就会产生这个结果。

const data = { name: "Alice" };
JSON.parse(data); // data 被转成 "[object Object]",报错

这个值已经解析过了,直接用就行。如果目的是深拷贝,用 structuredClone(data),不要走 stringify / parse 来回转。

Unexpected end of JSON input

JSON 还没读完,字符串就结束了。常见情况有两个:空字符串(JSON.parse(""))和被截断的响应(网络请求中断、文件只写了一半)。先打印原始字符串的长度。长度为 0 的话,问题不在 JSON 语法,而在传给解析器之前的环节。

不同环境的报错差异

同一个语法错误,在不同运行环境里的报错措辞不一样。整理一下常见环境的报错格式,方便搜索时对上号:

环境 / 运行时典型报错能看出什么
浏览器(Chrome / Node.js)Unexpected token < in JSON at position 0开头的 < 说明返回的不是 JSON 而是 HTML 错误页。去网络面板看实际响应
Node.jsUnexpected token } in JSON at position 142可以通过 position 数字定位
Pythonjson.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)行列号都有。空响应或 HTML 响应传给 json.loads() 时常见
Java(Jackson)JsonParseException: Unexpected character ('}' (code 125)): was expecting double-quote to start field name同时说明期望的字符和实际的字符

浏览器里如果看到 Unexpected token < in JSON at position 0,几乎可以肯定 API 返回了 HTML 错误页(404 或 500 页面),而不是 JSON。这时候应该怀疑请求 URL 和状态码,而不是 JSON 语法。

Python 里的 Expecting value: line 1 column 1 (char 0) 也是同一类问题。响应体为空、或者把非 JSON 内容传给了 json.loads()。最快的排查方式:先把原始响应打印出来看看。

调试步骤

报错只有几行的话肉眼就能修。API 响应或大文件则需要一个固定的排查顺序:

  1. 粘贴到 JSON 格式化工具,看报错行号和内容
  2. 往报错位置的前几行看。实际错误经常出现在报错位置之前的行(比如第 10 行漏了逗号,报错出现在第 11 行)
  3. 对照上面 5 个原因(尾逗号、单引号、无引号键、注释、BOM)逐一排查
  4. 如果是代码生成的 JSON,检查序列化部分。用字符串拼接手动构建 JSON 是最容易出 bug 的地方
  5. 如果是从 API 接收的 JSON,解析前先确认编码(特别是 GBK 问题)

fetch 接收响应时,先拿原始文本和状态码,再解析。这样可以一个地方就区分出 HTML 错误页、空响应、截断响应三种情况:

const response = await fetch("/api/data");
const raw = await response.text(); // 不用 response.json(),先拿原始文本

if (!response.ok) {
  console.error(`HTTP ${response.status}:`, raw.slice(0, 200));
} else if (!raw) {
  console.error("响应体为空"); // Unexpected end of JSON input 的典型原因
} else {
  try {
    const data = JSON.parse(raw);
  } catch (e) {
    console.error("JSON 解析失败:", e.message, raw.slice(0, 200));
  }
}

用 FormatArc 定位错误位置

知道 5 个原因之后,几百行的 JSON 文件里找到具体出错位置仍然是件麻烦事。用 JSON 格式化工具,粘贴进去就能看到报错行号和具体内容。

操作分 3 步:

  1. 打开 JSON 格式化工具
  2. 把 JSON 粘贴到左侧编辑器
  3. 点运行按钮

合法 JSON 会在右侧显示格式化结果。有语法错误的话,报错信息里会带行号,修好那一行再运行一次就行。

所有处理都在浏览器里完成,不会把数据上传到服务器。包含 API 密钥或个人信息的 JSON 也可以放心使用。

预防 JSON 报错

与其报错之后再修,不如养成几个习惯:

  • 生成 JSON 时用 JSON.stringify()(各语言的对应序列化函数),不要用字符串拼接
  • 编辑器保存时开启 JSON 校验(VS Code、IntelliJ、Sublime Text 都支持)
  • CI 里加一步校验。python -m json.tool < config.json 这种简单检查就能在部署前发现坏文件
  • 手动编辑时用支持实时校验的工具

另外,不要往不可信的在线工具里粘贴工作数据。怎么判断一个在线工具是否安全,见 在线工具安全检测。FormatArc 所有处理在浏览器内完成,不向外部传输数据。

JSON 不适合的场景

想写注释、想处理多行文本、想管理复杂嵌套配置——如果经常被 JSON 的约束卡住,可以考虑 YAML。YAML 支持注释,多行文本处理也更自然,作为配置文件通常更好读。

YAML 也有自己的坑:对缩进敏感,隐式类型转换等行为不太直观。两个格式需要时用 YAML JSON 转换工具 互相转,按场景分开用就行。

总结

JSON parse 报错的大部分场景都能归到上面 5 类模式:尾逗号、单引号、无引号键、注释、BOM。报错信息里的 Unexpected tokenposition 是排查线索,但文件大的时候交给工具更高效。JSON 的基本语法想回顾的话,看 JSON 语法完全指南;JSON 的格式化方法见 JSON 排版工具

CSV 数据需要转成 JSON 的话,可以用 CSV JSON 转换工具