JSON Toolkit

Why Chinese turns into \u4e2d\u6587

Bottom line: A \u4e2d\u6587 escape is legal Unicode, not an encoding failure. Real mojibake looks different, and telling them apart decides what you actually need to fix.

Beginner~3 min readPublished 2026-10-30Updated 2026-10-30
Unicode escaping versus real mojibake in JSON

Bottom line: treat \uXXXX output as legal escaping, confirm it round-trips through JSON.parse, and turn off pure-ASCII serialization such as ensure_ascii=False when you want readable Chinese; keep escaping only for transports that cannot carry non-ASCII.

Because it was escaped, not damaged.

JSON.parse('"\\u4e2d\\u6587"')  // "中文"

\u4e2d is 中 and \u6587 is 文. These are legal escape sequences; any parser restores them. Nothing is broken — it is just unreadable in logs, diffs and packet captures.

Who does the escaping

Tool Default Toggle
Python json.dumps Escapes (ensure_ascii=True) ensure_ascii=False
JavaScript JSON.stringify No escaping —
Java Jackson No escaping Optional
PHP json_encode No escaping since 5.4 —
Go encoding/json No escaping —

Python is by far the most common source. The default exists for a reason: pure ASCII output survives any transport. The cost is that every non-ASCII character becomes six characters.

Escaping versus mojibake

Escaping: \u4e2d\u6587, matching \uXXXX. Caused by serializer settings. Mojibake: 测试, 涓枃. Caused by writing UTF-8 bytes and reading them as Latin-1 or GBK.

Quick test: paste the text into a browser console as JSON.parse('"…"'). If it comes back readable, it was escaping. If it fails or stays garbled, it is an encoding mismatch — and the fix is to align the encodings, not to touch the serializer.

Turning it off

json.dumps(data, ensure_ascii=False)

Then verify downstream: some legacy systems genuinely rely on ASCII-only transport, particularly SMS gateways and older mail relays.

When escaping is the right choice

  • Transports that are hostile to non-ASCII (legacy HTTP headers, some SMS gateways)
  • JSON nested inside another JSON string, where escaping reduces quote conflicts
  • Log pipelines that truncate by bytes and would split a multi-byte character

Otherwise, prefer readability and turn it off.

FAQ

Why does Python escape Chinese by default?

Because ensure_ascii=True is the default, which guarantees pure ASCII output that survives any transport. The cost is that every non-ASCII character becomes six characters.

Should I turn off ensure_ascii?

Turn it off when readability matters. Then verify downstream — legacy HTTP headers, some SMS gateways and log pipelines that truncate by bytes may still rely on ASCII-only content.

What happens if the transport cannot carry non-ASCII?

Keep the escaping. When JSON is embedded inside another JSON string, or travels over a channel that is hostile to non-ASCII, escaping avoids quote conflicts and prevents multi-byte characters from being split.

Further reading