SyntaxError: Bad escaped character in JSON at position N 表示解析器在 JSON 字符串里发现了一个反斜杠(\),而它后面的字符不是 JSON 允许的转义字符之一。根据 RFC 8259 第 7 节,JSON 字符串只能转义双引号、反斜杠、正斜杠,以及控制字符转义 b、f、n、r、t,或者写作小写 u 后跟恰好四位十六进制数字的 Unicode 转义。
在实际调试中,这个错误通常来自一个被复制粘贴的值:Windows 路径(C:\Users\Ada)、JavaScript 或 shell 转义(\x1b)、正则表达式模式(\d+)、Python 风格的 Unicode 转义(\U0001F600),或者是从日志里被半反转义的字符串。修复方式不是「删掉反斜杠」,而是先确定这个字符串最终应该是什么值,然后写出能表示这个值的 JSON 文本。
本指南以 JavaScript JSON.parse() 的错误措辞为主,但同一规则适用于 Python json.loads()、Go encoding/json、Ruby JSON.parse、PHP json_decode、jq、Postgres jsonb 以及大多数严格的 JSON 解析器。
我遇到的是哪种字符串错误?
- Bad escaped character:一个
\后面跟了 JSON 不允许的东西,例如\x、\d、\'或\Users。- Bad control character:字符串里出现了原始的 tab、换行、NUL 字节或 ANSI ESC 字节。
- Unterminated string:字符串以
"开头但没有闭合。
30 秒修复法
- 跳到报告中的
position、line或column。 - 往前看一个字符,找那个反斜杠。
- 检查反斜杠后面的字符。
- 如果反斜杠本身就是数据,把它写成
\\。 - 如果这个转义属于其他语言(
\x、\d、\U),把它翻译成 JSON 语法。 - 如果反斜杠只是从带引号的日志行里复制来的,就多解析一层,而不是用正则去掉它。
例子:
{"path":"C:\Users\Ada\file.json"}
^
U is not valid after a JSON backslash
正确的 JSON 文本:
{
"path": "C:\\Users\\Ada\\file.json"
}
解析后,应用程序里实际的值仍然是:
C:\Users\Ada\file.json
双反斜杠只存在于 JSON 文本里。
错误长什么样
不同引擎的措辞略有差别:
// V8: Chrome, Node.js, Edge
SyntaxError: Bad escaped character in JSON at position 12
// Firefox
SyntaxError: JSON.parse: bad escaped character at line 1 column 13 of the JSON data
// Safari
SyntaxError: JSON Parse error: Invalid escape character \x
V8 的 position 通常指向反斜杠之后的字符,而不是反斜杠本身。在下面这段坏掉的 JSON 里,报告的字符是 \Users 里的 U:
{"path":"C:\Users\Ada\file.json"}
^^
\U is the bad escape
所以当消息说 position 12 时,要检查 position 12 前后一小段窗口。那个坏字符是有用的,但它前面的反斜杠才解释了 bug 的原因。
JSON 允许的全部转义
在 JSON 字符串里,反斜杠只能引出下列这些转义:
| JSON 转义 | 解析后的字符 | 备注 |
|---|---|---|
\" |
" |
JSON 字符串内的双引号必须转义 |
\\ |
\ |
字面反斜杠必须转义 |
\/ |
/ |
可选;/ 不转义也合法 |
\b |
退格 | U+0008 |
\f |
换页 | U+000C;这就是 \file 在 Windows 路径里危险的原因 |
\n |
换行 | U+000A |
\r |
回车 | U+000D |
\t |
制表符 | U+0009 |
\uXXXX |
Unicode 码元 | 小写 u 后恰好四位十六进制 |
其他所有形式都是无效 JSON:\x、\'、\d、\s、\w、\0、\v、\e、\U、\u{1F600}、\N{...}、\cA,以及像 \u12 这样的短 Unicode 转义。
快速修复对照表
如果你已经清楚最终值应该是什么,就用这张表。
| 坏掉的 JSON 文本 | 为什么失败 | 合法的 JSON 文本 |
|---|---|---|
{ "path": "C:\Users\Ada\file.json" } |
\U 和 \A 无效;\f 虽然合法,但会变成换页符,不是路径分隔符。 |
{ "path": "C:\\Users\\Ada\\file.json" } |
{ "path": "C:/Users/Ada/file.json" } |
这不会失败。正斜杠不需要转义。 | 如果接收方接受正斜杠,就保留原样。 |
{ "color": "\x1b[32mOK\x1b[0m" } |
JSON 没有 \xNN 转义。 |
{ "color": "\u001b[32mOK\u001b[0m" } |
{ "name": "O\'Brien" } |
JSON 字符串里的单引号不需要转义。 | { "name": "O'Brien" } |
{ "pattern": "^\d{4}-\d{2}-\d{2}$" } |
\d 是正则转义,不是 JSON 转义。 |
{ "pattern": "^\\d{4}-\\d{2}-\\d{2}$" } |
{ "char": "\u12" } |
\u 后面必须跟正好 4 位十六进制数字。 |
{ "char": "\u0012" } |
{ "emoji": "\u{1F600}" } |
JavaScript 源代码字符串支持这种写法,JSON 不支持。 | { "emoji": "😀" } 或 { "emoji": "\uD83D\uDE00" } |
有一个别扭的细节值得单独警告:\f 是合法的 JSON 转义。如果 Windows 路径里包含 \file,解析器会把它变成一个换页符加上 ile。解析可能会成功,但路径值已经被损坏了。这就是为什么盲目「修复」路径字符串是有风险的。
原因 1:Windows 路径被复制进 JSON
Windows 路径看起来无害,因为人眼把反斜杠读成路径分隔符:
{ "downloadDir": "C:\Users\Ada\Downloads" }
JSON 把反斜杠读成一个转义序列的开头。它看到 \U,然后就停下了,因为大写 U 不是一个 JSON 转义。
在 JSON 里写双反斜杠:
{
"downloadDir": "C:\\Users\\Ada\\Downloads"
}
或者,如果接收程序接受正斜杠,就用正斜杠:
{
"downloadDir": "C:/Users/Ada/Downloads"
}
对配置文件来说,正斜杠通常更不容易出错。对严格的仅 Windows 值来说,双反斜杠是可移植的 JSON 表示法。
原因 2:把 JavaScript 源字符串和 JSON 文本混为一谈
这里是网上很多示例意外把人搞糊涂的地方。有两层:
- JavaScript 源字符串语法
- 这个 JavaScript 字符串里面的 JSON 文本语法
下面这段 JavaScript 源代码是合法的:
const raw = '{"path":"C:\\Users\\Ada"}';
JSON.parse(raw);
但真正到达解析器的 JSON 文本是:
{"path":"C:\\Users\\Ada"}
如果你想在 JavaScript 里测试一段坏掉的 JSON 样本,又不希望 JavaScript 自己先吃掉反斜杠,就用 String.raw:
const broken = String.raw`{"path":"C:\Users\Ada"}`;
JSON.parse(broken);
这会抛出 Bad escaped character,因为 JSON.parse() 收到的是真正坏掉的 JSON 文本。
阅读堆栈时用这个心智模型:如果 JSON 来自 .json 文件、HTTP 响应体、localStorage 值或数据库字符串,就修 JSON 文本本身。如果 JSON 在一个 JavaScript 源字符串里,可能需要一层给 JavaScript 的转义,再一层给 JSON 的转义。
原因 3:借用其他语言的转义
JSON 接受 \n 和 \t,但不接受许多在别的编程语言里很常见的转义:
{ "code": "\x1b[0m", "name": "O\'Brien" }
合法 JSON:
{
"code": "\u001b[0m",
"name": "O'Brien"
}
常见的「假朋友」:
| 转义 | 在这些语言里合法 | JSON 修复方式 |
|---|---|---|
\x1b |
JavaScript、Python、许多 shell | \u001b |
\' |
JavaScript/Python 的单引号字符串 | 用 ',不加反斜杠 |
\0 |
JavaScript/Python 的 NUL 简写 | \u0000 |
\v |
JavaScript 的垂直制表符 | \u000b |
\U0001F600 |
Python 的 Unicode 转义 | 字面 UTF-8 emoji 或代理对 |
\u{1F600} |
JavaScript 的 Unicode 码点转义 | 字面 UTF-8 emoji 或代理对 |
如果生产方是你自己的代码,不要一个一个手工翻译。构造正常的对象,让语言自带的 JSON 序列化器写出合法的 JSON。
原因 4:正则模式存到 JSON 配置里
正则有它自己的转义语言。JSON 字符串有另一套独立的转义语言。正则的反斜杠必须先熬过 JSON 解析,才能到达正则引擎。
坏掉的 JSON 配置:
{ "datePattern": "^\d{4}-\d{2}-\d{2}$" }
合法的 JSON 配置:
{
"datePattern": "^\\d{4}-\\d{2}-\\d{2}$"
}
JSON 解析之后,应用程序看到的字符串是:
^\d{4}-\d{2}-\d{2}$
只有到这一步,它才应该变成一个正则:
const config = JSON.parse('{"datePattern":"^\\\\d{4}-\\\\d{2}-\\\\d{2}$"}');
const re = new RegExp(config.datePattern);
同样的规则适用于 \s、\w、\b、命名分组、后行断言示例,以及替换字符串。如果这个反斜杠是留给后面的解析器用的,就在 JSON 里把它写成双份。
原因 5:畸形的 Unicode 转义
JSON 的 Unicode 转义是定长的:
{ "char": "\u12" }
合法 JSON:
{
"char": "\u0012"
}
u 必须小写,后面必须跟恰好四位十六进制数字:0-9、a-f 或 A-F。
下面这些都不是 JSON 的 Unicode 转义:
"\u{2028}" // JavaScript 源代码风格,不是 JSON
"\U00002028" // Python 风格,不是 JSON
"\u20G0" // G 不是十六进制数字
基本多文种平面之外的字符,比如许多 emoji 和一些数学符号,可以直接以 UTF-8 形式存进 JSON 里:
{
"emoji": "😀"
}
如果要转义,则表示为 UTF-16 代理对:
{
"emoji": "\uD83D\uDE00"
}
避免出现孤立代理,比如没有配对低位代理的 \uD83D。有些解析器把它们当作码元接受,但对格式良好的 Unicode 有要求的下游系统可能会拒绝。
原因 6:手工拼接的 JSON 字符串
这是这个 bug 的生产版本:
// Unsafe: userInput may contain backslashes, quotes, or newlines.
const payload = '{"message":"' + userInput + '"}';
如果 userInput 是 C:\Users\Ada,输出的文本就是无效 JSON。如果它含有 ",JSON 会以另一种方式坏掉。如果它含有原始的换行,你可能会得到一个 bad control character 错误。
用序列化器:
const payload = JSON.stringify({
message: userInput,
path: 'C:\\Users\\Ada\\file.json',
code: '\x1b[32mOK\x1b[0m',
});
JSON.stringify() 会处理 JSON 特有的转义。结果是合法的 JSON 文本:
{
"message": "...",
"path": "C:\\Users\\Ada\\file.json",
"code": "\u001b[32mOK\u001b[0m"
}
同样的原则适用于其他语言:
import json
payload = json.dumps({
"path": r"C:\Users\Ada\file.json",
"pattern": r"^\d+$",
})
body, err := json.Marshal(map[string]string{
"path": `C:\Users\Ada\file.json`,
"pattern": `^\d+$`,
})
如果你正在修的是生产方,这才是真正的修复。在下游给无效 JSON 打补丁,只会掩盖坏文本的产生位置。
如何定位坏掉的转义
对于粘贴进来的 JSON,下面这个小助手可以让 V8 的 position 附近更容易看清楚:
function showJsonParseContext(raw) {
try {
JSON.parse(raw);
console.log('Valid JSON');
} catch (error) {
const message = String(error.message);
const match = message.match(/position (\d+)/);
if (!match) {
console.log(message);
return;
}
const pos = Number(match[1]);
const start = Math.max(0, pos - 24);
const end = Math.min(raw.length, pos + 24);
const excerpt = raw.slice(start, end);
console.log(message);
console.log(JSON.stringify(excerpt));
console.log(' '.repeat(pos - start) + '^');
}
}
const raw = String.raw`{"path":"C:\Users\Ada\file.json"}`;
showJsonParseContext(raw);
JSON.stringify(excerpt) 是特意用的。它会把反斜杠和控制字符显示成可见的转义,这在 bug 是不可见的空白或过度转义时正是你需要的。
对于 Firefox 那种 line 和 column 的报错,先跳到那一行,再检查那一行上的字符串字面量。如果确切的列落在反斜杠后面,就把前一个字符也一起看进去。
用修复工具还是直接拒绝这段内容?
以下情况适合用修复工具:
- 你在清理一段粘贴过来的片段。
- 你在调试一条日志行。
- 你在审查 LLM 输出。
- 你可以肉眼确认修复后的值。
- 这个值不涉及资金流动、权限、删除或不可逆的状态变更。
以下情况应该拒绝这段内容,去修生产方:
- JSON 来自 API 契约。
- 这个值影响计费、权限、安全或数据删除。
- 解析器不得不在多种可能含义之间猜测。
- 一段路径、正则或转义序列可能是合法的,但语义上是错的。
举个例子,修复 C:\Users\Ada\file.json 不只是一个语法操作。\file 里的 \f 是合法转义,所以某个工具可能会解析出一个换页符,而不是保留反斜杠。得由人或生产方代码来决定正确的路径。
本站的 JSON Fix 工具最适合当作浏览器本地的调试助手:粘贴文本,检查输出,然后对修复后的 JSON 做校验。它不应该成为畸形生产载荷的静默摄入层。
如何安全地反转义 JSON
有时候反斜杠没有错,是 JSON 被双重编码了。你可能在日志里看到这样的东西:
{\"name\":\"Ada\",\"path\":\"C:\\\\Users\\\\Ada\"}
不要用 replace(/\\/g, '') 一把梭。那会破坏真正的转义。
一次解析一层合法的 JSON:
// The outer value is a JSON string that contains JSON text.
const wrapped = '"{\\"name\\":\\"Ada\\",\\"path\\":\\"C:\\\\\\\\Users\\\\\\\\Ada\\"}"';
const once = JSON.parse(wrapped);
// once is: {"name":"Ada","path":"C:\\Users\\Ada"}
const data = JSON.parse(once);
// data is: { name: "Ada", path: "C:\\Users\\Ada" }
如果第一次解析就抛出 Bad escaped character,那就不是简单的编码问题。它本身就是无效的 JSON 文本,需要针对性地修复。
预防清单
- 永远不要把用户字符串拼进 JSON。
- 使用
JSON.stringify()、json.dumps()、json.Marshal(),或者你所在平台的 JSON 序列化器。 - 正则模式存进 JSON 时用双反斜杠。
- 只要接收方接受,路径就优先用正斜杠。
- 从日志、shell 和文档里复制来的示例要加引号并测试。
- 在 CI 里用真正的解析器校验生成的
.json文件。 - 在解析器报错位置附近打印一段安全的预览,不要打印整个载荷。
- 把自动修复视为开发者工作流,而不是生产契约。
常见问题
「Bad escaped character in JSON」是什么意思?
JSON 字符串里的一个反斜杠后面跟了一个 JSON 不允许出现在 \ 之后的字符。合法的转义是 "、\、/、b、f、n、r、t 和 uXXXX。
JSON 里的 Windows 路径怎么修?
把路径里每个反斜杠都写成 \\,例如 C:\\Users\\Ada\\file.json。如果接收程序接受正斜杠,C:/Users/Ada/file.json 就是合法的 JSON,而且更好读。
我的正则在 JavaScript 里行,为什么在 JSON 里不行?
JSON 解析器先看到这个字符串,然后正则引擎才看到。像 \d 这样的正则转义在 JSON 里必须写成 \\d,这样解析出来的字符串里才仍然是 \d。
\x1b 在 JSON 里合法吗?
不合法。\xNN 在 JavaScript、Python 和 shell 示例里很常见,但 JSON 不支持它。用 \u001b 表示 ANSI ESC 字符,或者在序列化日志之前把 ANSI 颜色码去掉。
这和「Bad control character」是同一个错误吗?
不是。「Bad escaped character」是指反斜杠后面的字符无效;「Bad control character」是指字符串里出现了一个原始的控制字节,比如字面的换行、tab、NUL 或 ESC 字节。
JSON 修复工具能自动修复坏的转义吗?
有时可以,用于目标值明显的粘贴片段。不要静默自动修复 API 载荷、安全敏感数据、支付、权限、删除操作,也不要自动修复那些 \f、\n、\t 可能合法但并非预期的值。
JSON 怎么反转义?
用 JSON.parse() 一次解析一层。一个被双重编码的值第一次解析后变成一个普通 JSON 字符串,再解析一次才是真正的对象或数组。不要用正则去掉反斜杠,那会破坏合法的转义。
怎样在源代码里预防这个错误?
构造原生值,然后用 JSON.stringify() 或你所用语言里等价的序列化器输出。不要用字符串拼接来组装 JSON。
立刻修复
- JSON Fix —— 在浏览器里定位并修复无效的转义。
- JSON Stringify —— 转义与反转义 JSON 字符串字面量。
- 把 JSON 转义为字符串字面量 —— 处理嵌套和双重编码的 JSON。
- JSON 里的 Bad Control Character —— 原始控制字节和已转义文本的区别。
- JSON 中的未终止字符串 —— 字符串没闭合时的情形。
- 如何修复 JSON.parse 的 Unexpected Token 错误 —— 更全面的 JSON 解析器错误指南。
参考资料
- RFC 8259 section 7 —— JSON 字符串语法和完整的转义列表。
- MDN JSON.parse —— JavaScript 解析器的行为和
SyntaxError处理。 - MDN JSON.stringify —— 从 JavaScript 值安全生成 JSON。
- MDN JSON.parse bad parsing errors —— 常见的浏览器 JSON 解析错误消息。
- MDN String and UTF-16 —— UTF-16 码元、代理对和格式良好的字符串。
最后审阅于 2026 年 7 月。