Unexpected token } in JSON at position 247.
Nearly every developer has seen this. It tells you something is wrong near character 247 — but not what is wrong. And JSON errors are notoriously indirect: the actual mistake usually sits dozens of characters before the reported position.
This handbook is organized by symptom, so you can classify the problem first, then jump to the fix. Each category links to a dedicated deep-dive article; this page gives you the decision path and the minimum action to unblock.
Locate your symptom first (diagnostic table)
| What you see | Most likely cause | Jump to |
|---|---|---|
| Unexpected token < or Unexpected token o | Response isn't JSON (HTML error page / undefined) | Type 1 |
| Unexpected token } / ] / , | Trailing comma, extra bracket | Type 1 |
| Unexpected end of JSON input | Truncated data, empty string | Type 1 |
| Chinese becomes \uXXXX | ASCII escaping enabled during serialization | Type 2 |
| Chinese shows as ???? or é”± | Encoding mismatch (UTF-8 vs GBK) | Type 2 |
| is not valid JSON / Schema validation fails | Missing required field, wrong type | Type 3 |
| Two JSONs look identical but compare unequal | Key order, whitespace, number precision | Type 4 |
Can't tell? Paste it into the JSON formatter. It highlights the first syntax error and its position — far faster than reading stack traces.
Type 1: Syntax errors (JSON.parse fails)
JSON syntax is far stricter than JavaScript object literals. That's the root of most errors.
Strictness comparison
| Syntax | JavaScript | JSON | Notes |
|---|---|---|---|
| Quoted keys | Optional | Required, double quotes | {name:"a"} is invalid |
| String quotes | Single or double | Double quotes only | {'a':1} is invalid |
| Trailing comma | Allowed | Forbidden | {"a":1,} is invalid |
| Comments | Allowed | Not supported | // and /* */ both fail |
| undefined / NaN | Allowed | Not valid values | Use null |
| Functions, Date objects | Allowed | Not supported | Dates must be strings |
Three frequent traps
Trap 1: the server didn't return JSON
SyntaxError: Unexpected token < in JSON at position 0
An error at position 0 almost always means the body is an HTML error page (starting with <) or plain text. Common causes: 404/500 responses, expired session redirecting to a login page, or a gateway error page.
Debug it: log the raw response body before calling JSON.parse().
Trap 2: BOM header
JSON with a UTF-8 BOM carries an invisible \uFEFF at the start, producing Unexpected token .
# Check whether a file has a BOM
head -c 3 file.json | xxd | head -1 # efbbbf means BOM present
Trap 3: truncated data
Unexpected end of JSON input usually means: empty string, null, or the transfer was cut short (large response timeout, stream not fully read).
👉 Full error list with fixes: JSON.parse Unexpected token — complete fix guide.
Type 2: Chinese & encoding issues
These are the most confusing, because the data is syntactically valid — it just looks wrong.
Symptom A: Chinese becomes \uXXXX
{"name":"\u5f20\u4e09"}
This isn't an error — it's Unicode escaping, a legal JSON representation that decodes back to "张三". It appears because serialization was configured with ensure_ascii=True (Python) or equivalent.
If you want literal Chinese characters in the file:
# Python: disable ASCII escaping
json.dumps(data, ensure_ascii=False)
// JavaScript: JSON.stringify does not escape Chinese by default
JSON.stringify({name: "张三"}) // {"name":"张三"}
👉 See Chinese turning into \uXXXX escapes.
Symptom B: mojibake (???? or é”±)
This is a character-encoding mismatch, unrelated to JSON syntax:
| Garbled form | Cause |
|---|---|
| ???? | Written with an encoding that can't represent Chinese (ASCII, Latin-1) |
| é”± | UTF-8 bytes interpreted as GBK |
| 锟斤拷 | UTF-8 → GBK → back again; irreversible |
Golden rule: the JSON spec defines UTF-8 as the default encoding. Use UTF-8 on both read and write sides and mojibake disappears.
# Check a file's actual encoding
file -I data.json
# Convert GBK -> UTF-8
iconv -f GBK -t UTF-8 data.json > data.utf8.json
Type 3: Structure & Schema validation failures
Syntactically valid, but structurally wrong.
Common validation failures
| Error | Cause |
|---|---|
| is a required property | Missing required field |
| is not of a type 'string' | Type mismatch (number written as string, etc.) |
| additionalProperties not allowed | Field not defined in the Schema |
| does not match pattern | Fails the regex constraint |
Frequent gotcha: 1 and "1" are different types in JSON. An API returning "age": "30" fails a Schema expecting integer.
Debug it: run the JSON Schema validator to get the complete error list — it reports every problem, not just the first.
👉 See JSON Schema required / type validation failures.
Type 4: Data diff & comparison
Two JSONs that "look the same" but compare unequal usually differ because of:
- Key order — JSON objects are semantically unordered, but string comparison is order-sensitive.
- Whitespace / indentation — serialization formatting differences.
- Number precision — floating point (
0.1 + 0.2 !== 0.3), or integers beyond IEEE 754 safe range. - Array order — arrays are ordered; a different order means different data.
Do it right: compare semantically (parse, then compare recursively), never as strings. The JSON Diff tool shows the differing nodes across both trees.
General debugging workflow (works for any JSON problem)
Four steps that resolve the vast majority of cases:
1. Inspect the raw bytes, not the parsed result
Print the raw string before JSON.parse(). Many "JSON errors" aren't JSON at all (HTML error page, empty response, truncated stream).
2. Let a tool point at the first error Paste into the JSON formatter. Syntax errors get highlighted with row/column — remember the real mistake is usually before the reported spot (a missing quote only surfaces at the next token).
3. Bisect to narrow it down For large files, split the JSON in half and test each half. Repeat a few times to isolate the offending field.
# Quick command-line validation
python3 -m json.tool data.json > /dev/null && echo "Valid JSON" || echo "Invalid JSON"
# or
jq . data.json > /dev/null && echo "Valid JSON"
4. Re-validate after fixing If the API still errors once syntax passes, the problem is structure, not syntax — move to Schema validation.
Troubleshooting toolkit
| Need | Tool | |---|---| | Format / highlight syntax errors | JSON formatter | | Diff two JSON documents | JSON Diff | | Validate structure against a Schema | JSON Schema validator | | Extract fields from large JSON | JSONPath query | | JSON to Java / Go / TS classes | To Java · To Go |
Every tool above runs locally in your browser — safe to paste production JSON into. Open the Network panel (F12) and verify it yourself.
FAQ
Q: Why does the error position usually point past the real mistake?
Because the parser only notices something is wrong when it reaches a later character. In {a:1}, the unquoted a isn't flagged until the parser hits the colon or the next token. The reported position is where the problem surfaces, not where it started.
Q: JSON.parse succeeded but the data is wrong — why?
Valid syntax doesn't mean correct semantics. Common cases: numbers stored as strings, wrong nesting level, an array serialized as an object, large-integer precision loss. Catch these with Schema validation or a diff.
Q: How do I debug very large JSON (hundreds of MB)?
Browser tools hit memory limits. Use the command line: jq for streaming and locating, python3 -m json.tool for validation. Start with jq 'keys' to see the top-level shape, then drill down.
Q: How do I stop JSON problems from recurring? Add a CI gate: validate API responses against a Schema and snapshot-diff them. That catches most structural changes before merge.
Summary
The core approach: classify first, then drill down.
- Syntax error → look before the reported position; check quotes, commas, comments
- Chinese issue → decide whether it's Unicode escaping (legal) or mojibake (encoding mismatch)
- Structure issue → use a Schema validator for the full error list
- Diff issue → compare semantically, never as strings
Bookmark this handbook. Next time you hit Unexpected token, match your symptom against the table instead of counting characters.
Related Tools
Related Articles
JSON Schema Reports "required" Property Missing — How to Locate and Fix
JSON Schema validation says a required property is missing, or type mismatch? Explains required / additionalProperties / type pitfalls and how to locate the exact level with our validator.
JSON Shows Chinese as \uXXXX Escapes After Formatting — How to Get Readable Text Back
Why does formatted JSON turn Chinese into \uXXXX Unicode escapes, and how do you convert it back to readable text? Explains the cause and shows a one-click fix, all processed locally in your browser.
Best Online JSON Formatter Tools Comparison (2026)
Comparing 5 popular online JSON formatter tools across features, speed, privacy, and pricing. ToolVault stands out with local processing, Unicode safety, and free unlimited use.