Unexpected token in JSON: 12 common causes and how to find them
The 'Unexpected token in JSON' error tells you where but not why. Here are 12 specific causes and how to fix each.
title: "Unexpected token in JSON: 12 common causes and how to find them" slug: "unexpected-token-in-json" date: "2026-06-08" description: "The 'Unexpected token in JSON' error tells you where but not why. Here are 12 specific causes and how to fix each." keywords:
- unexpected token in JSON
- unexpected token in JSON at position
- JSON syntaxerror
- JSON parser error
- unexpected character JSON ogTitle: "Unexpected token in JSON · 12 common causes · jsonzen"
V8's error message — SyntaxError: Unexpected token X in JSON at position N — gives you two facts: the character it stumbled on (X) and the byte offset from the start of the string (N). What it doesn't give you is why that character is there or what you actually need to change. The fix almost always lives somewhere upstream of position N, not at it. Here are 12 specific causes, each with an example of what goes wrong and exactly how to fix it.
What the error means
V8's JSON parser is strict — stricter than most developers expect. It implements the JSON spec (RFC 8259) with zero tolerance for the extensions that JavaScript itself allows. When it hits a character it doesn't expect, it halts immediately and reports the character and byte offset.
Two things to know about position N:
- Positions are counted from byte 0 (the very first character of the string you passed to
JSON.parse), not from line 1. Position 0 is the first character. - The reported position is where the parser gave up, not necessarily where you made the mistake. A missing comma at position 12 might not surface until the parser hits the next key at position 18.
How to find the position visually:
- Most editors have a "Go to character offset" or "Go to position" feature in their command palette. In VS Code:
Ctrl+Ggoes to line, but you can also use the column indicator in the status bar to count along a line. - Paste the JSON into the JSON Validator — it converts the raw byte offset to a human-readable line and column number automatically, which is far easier to act on.
- In browser DevTools, when an API response fails to parse, the Network tab shows the raw response and the Console shows the error with position. Use DevTools' pretty-print to count to the line.
12 specific causes
1. Trailing comma in object
JSON does not allow a comma after the last key-value pair in an object. JavaScript and most modern languages permit it; JSON does not.
// Wrong
{"name": "Alice", "age": 30,}
// Right
{"name": "Alice", "age": 30}
Error: Unexpected token } in JSON at position 25
The parser sees a } where it expected another key (because the comma said "more items coming"). Remove the trailing comma.
2. Trailing comma in array
Same rule applies to arrays: no comma after the final element.
// Wrong
{"colors": ["red", "green", "blue",]}
// Right
{"colors": ["red", "green", "blue"]}
Error: Unexpected token ] in JSON at position 34
This one bites especially hard when you delete the last item from an array and forget to clean up the comma that used to separate it from the new last item.
3. Single quotes around string values
JSON strings must use double quotes. Single quotes are not valid string delimiters in JSON, even though JavaScript accepts them for string literals.
// Wrong
{"status": 'active'}
// Right
{"status": "active"}
Error: Unexpected token ' in JSON at position 10
The parser sees ' where it expects " to open a string (or a value token like true, false, null, [, {, or a digit). Replace every string-delimiting single quote with a double quote — but do it surgically, not with a global find-replace, since apostrophes inside string values are valid and should stay.
4. Single quotes around keys
Keys in JSON objects are strings and follow the same rule: double quotes only.
// Wrong
{'username': "bob"}
// Right
{"username": "bob"}
Error: Unexpected token ' in JSON at position 1
Position 1 here (the second byte) is the ' that opened the key. The parser expected " or } immediately after {.
5. Unquoted keys
JavaScript object literal syntax allows bare (unquoted) identifiers as keys. JSON does not. Every key is a string and must be quoted.
// Wrong
{id: 42, name: "Carol"}
// Right
{"id": 42, "name": "Carol"}
Error: Unexpected token i in JSON at position 1
If you're serializing a JavaScript object, use JSON.stringify(obj) and let the runtime produce valid JSON. Don't hand-convert JS object literals to JSON by adding quotes manually — it's easy to miss one.
6. JavaScript-style comments
Neither // line comments nor /* */ block comments are part of the JSON specification. Every conformant JSON parser rejects them.
// Wrong
{
// user id
"id": 1,
"role": "admin" /* superuser */
}
// Right
{
"id": 1,
"role": "admin"
}
Error: Unexpected token / in JSON at position 4
If you need annotated config files, switch to JSONC (.jsonc, supported by VS Code and TypeScript's tsconfig.json) or JSON5 (.json5), which both allow // and /* */ comments. Don't strip comments with a regex preprocessor and call the result "JSON" — that masks the real issue.
7. Smart / curly quotes from rich-text editors
Text pasted from Word, Google Docs, Notion, Slack, or any rich-text source often carries typographic " (U+201C) and " (U+201D) instead of the straight ASCII " (U+0022) that JSON requires. They look nearly identical in most fonts. This is one of the sneakiest causes because the characters are visually indistinguishable.
// Wrong — curly left/right double quotes
{"title": "Hello world"}
// Right — straight ASCII double quotes
{"title": "Hello world"}
Error: Unexpected token in JSON at position 0 (the character shown is the curly quote, encoded as three UTF-8 bytes E2 80 9C)
The tell is a parse failure at or near position 0, or anywhere a string delimiter appears. A hex view of the file will show E2 80 9C where you expect 22. Fix by doing a targeted find-and-replace: " → " and " → ". The JSON Repair tool handles this automatically.
8. Trailing characters after the JSON ends
A valid JSON document is a single value. Any characters after the outermost } or ] — a stray extra brace, a newline followed by undefined, a second JSON blob, anything — will cause the parser to error.
// Wrong — extra closing brace after the document ends
{"ok": true}}
// Right
{"ok": true}
Error: Unexpected token } in JSON at position 12
This often surfaces when you concatenate API responses, when a template engine emits extra output after the JSON block, or when JSON.stringify output is wrapped in a function call like callback({...}) (JSONP-style). Strip everything after the closing delimiter of the root value.
9. Missing comma between two object properties
Leave out a comma between two key-value pairs and the parser hits a second " where it expects either , or }.
// Wrong
{
"first": "Alice"
"last": "Smith"
}
// Right
{
"first": "Alice",
"last": "Smith"
}
Error: Unexpected token " in JSON at position 20
Position 20 is the opening quote of "last". The parser expected , or } after the value "Alice", not another string. This tends to appear when you add a new property to a handwritten JSON object and forget the comma after the preceding line.
10. Missing comma between two array items
Same principle in arrays: every two consecutive elements must be separated by a comma.
// Wrong
["alpha" "beta" "gamma"]
// Right
["alpha", "beta", "gamma"]
Error: Unexpected token " in JSON at position 8
The parser read "alpha" as the first element, then expected , or ]. When it found " (the start of "beta"), it gave up at position 8. Add the missing commas.
11. Newline inside a string literal without escape
A raw (literal) newline character inside a JSON string is not allowed. The newline must be represented as the two-character escape sequence \n. This catches people who build JSON by string interpolation or heredoc rather than via a serializer.
// Wrong — literal newline in the string value
{
"message": "line one
line two"
}
// Right
{
"message": "line one\nline two"
}
Error: Unexpected token in JSON at position 22 (the token shown is the literal newline character, U+000A)
The safest fix: always generate JSON using JSON.stringify() or a library that handles escaping for you. If you're receiving this from an external source, run it through JSON Repair which escapes bare control characters automatically.
12. Unescaped double quote inside a string
A double quote character inside a string value must be escaped as \". An unescaped " terminates the string early and leaves the remainder as garbage that the parser can't interpret.
// Wrong — unescaped quote in value
{"quote": "She said "hello" to me"}
// Right
{"quote": "She said \"hello\" to me"}
Error: Unexpected token h in JSON at position 18
Position 18 is the h in hello — the parser thinks the string ended at the second " and then sees hello as an unknown token. Escape every double quote that appears inside a string value as \". Backslashes themselves must be escaped as \\.
How to find the position fast
When you see "Unexpected token X at position N", here's how to translate N into something actionable:
In your editor:
- VS Code: open the file, click in the editor, look at the status bar. It shows
Ln X, Col Y. To jump to a byte offset, useCtrl+Gto go to a line number, then count columns. For large files, a plugin like "Jump to Offset" does byte-level navigation directly. - Vim/Neovim:
gofollowed by a count jumps to that byte offset (42gojumps to byte 42). - Sublime Text:
Ctrl+Gfor line:column navigation.
Faster: use a validator that reports line/col: Paste into the JSON Validator and it converts the raw position to line and column numbers, highlights the error in context, and lists all errors in the document — not just the first one.
In the browser:
DevTools' Console shows SyntaxError: Unexpected token X in JSON at position N for failed JSON.parse calls. Switch to the Network tab, find the request, click Preview — DevTools pretty-prints the response and you can visually scan near the flagged position. The Sources tab lets you search the raw response.
One important thing: position N is a byte offset from the first character of the string you passed to JSON.parse. If that string came from response.text() or a file read, position 0 is the very first character. If there's a BOM (byte-order mark) prepended to the file, position 0 is already wrong — the BOM itself is 3 bytes, so position 0 is actually the E in EF BB BF, not {. Strip the BOM first.
The pragmatic fix
For one-off errors: paste the broken JSON into JSON Repair. It handles 8 of the 12 categories above automatically — trailing commas (1, 2), quote normalization (3, 4, 7), unquoted keys (5), missing commas (9, 10), and control character escaping (11). For causes 6 (comments), 8 (trailing characters), and 12 (unescaped quotes), it does the right thing in most cases too. For a quick fix without having to understand the spec, repair is the fastest path.
For LLM-generated JSON in bulk: models hallucinate trailing commas, unquoted keys, and missing quotes fairly regularly, especially for complex schemas. Pipe their output through the jsonrepair library (the same library jsonzen uses under the hood) as a normalization step before you call JSON.parse:
import { jsonrepair } from 'jsonrepair'
const raw = await llm.generate(prompt)
const fixed = jsonrepair(raw)
const data = JSON.parse(fixed)
This is more reliable than wrapping JSON.parse in a try/catch and hoping for the best.
For preventing future errors:
- Validate JSON inputs at your API boundary — don't let malformed JSON propagate deep into your application where errors are harder to trace.
- Configure your editor to lint
.jsonfiles: VS Code does this by default; other editors need a plugin or language server. - For config files that need comments, use
.jsoncor.json5explicitly and configure your toolchain to parse them accordingly. Don't shim comments into.jsonfiles. - When generating JSON programmatically, always use a serializer. Never build JSON by string concatenation.
TL;DR
| Cause | Fix |
|---|---|
| Trailing comma in object | Remove comma after last property |
| Trailing comma in array | Remove comma after last element |
| Single-quoted string values | Replace '...' with "..." for string delimiters |
| Single-quoted keys | Replace 'key' with "key" |
| Unquoted keys | Quote every key; use JSON.stringify for JS objects |
| JS comments | Delete them; use .jsonc if you need annotations |
| Smart/curly quotes | Replace " / " with straight " |
| Trailing characters | Delete everything after the root } or ] |
| Missing comma in object | Add , after each property except the last |
| Missing comma in array | Add , between every element |
| Literal newline in string | Replace raw newline with \n escape |
| Unescaped " in string | Replace " inside strings with \" |
For anything mechanical, JSON Repair handles most of these automatically. For understanding why the error happened and where the problem actually is, the JSON Validator gives you the line and column with full context.