It's a Tuesday afternoon, your webhook handler is failing in production, and the only clue you have is SyntaxError: Unexpected token in JSON at position 0. The payload looks fine when you open it in your editor — no red underlines, the braces line up — but the parser flatly refuses. Welcome to the JSON parse error: a class of bug where the file is wrong in a way no one bothered to write a good message about.
JSON parse errors fall into a small number of categories, and once you can name the category you're looking at the fix is usually a one-liner. This is the field guide.
The seven categories of JSON parse error
Almost every "my JSON won't parse" problem is one of these seven:
- Syntax — missing commas, trailing commas, unquoted keys, mismatched brackets. The parser saw a character it didn't expect.
- Value —
NaN,Infinity,undefined, hex literals. The grammar is right but the value isn't legal JSON. - Encoding — UTF-8 BOM, smart quotes, non-UTF-8 input. The bytes themselves are wrong before parsing even starts.
- Schema — the JSON parses fine, but a downstream consumer expected a string and got a number. Not really a parse error, but often misreported as one.
- Type — integer overflows, precision loss on big floats, dates encoded as strings that downstream code tries to parse as numbers.
- Semantic — duplicate keys, interpretation-dependent ordering, the JSON is valid but ambiguous.
- Environmental — truncated payload, chunked transfer that didn't reassemble, the file is literally incomplete.
The remaining sections walk through the four categories that cause roughly 90% of the pain.
Syntax errors — what the parser actually rejects
Syntax errors are the everyday case. They're also the easiest to fix once you know what to look for.
Missing commas between array or object items. {"a": 1 "b": 2} fails because there's no separator between the two key-value pairs. The error message usually points to "b", but the actual fix is earlier — add the comma after 1.
Trailing commas. [1, 2, 3,] is invalid strict JSON. It's been tolerated by JSON5 and most language-level parsers since around 2019, but plenty of backends still reject it — notably Python json, Go encoding/json, and the JSON parsers built into older HTTP libraries. If you control the producer, fix it there. If you don't, run the input through a tolerant formatter first.
Unquoted keys. {name: "alice"} is a JavaScript object literal, not JSON. The number-one source of this mistake is copy-paste from a JavaScript file. Keys must be double-quoted strings; single quotes don't count either.
Mismatched brackets. An extra ] or a missing } usually shows up with a wildly misleading line number, because the parser doesn't know the document is malformed until it reaches the end. The JSON formatter highlights the position the parser actually choked on, which is closer to the truth than "line 1247".
Value errors — things JSON literally can't hold
The JSON spec is more restrictive than most people remember. A surprising number of values that work fine in JavaScript are flat-out invalid in JSON.
NaN, Infinity, and -Infinity. None of these are valid JSON. JSON.stringify(NaN) in the browser returns the string "null" rather than throwing — which means you can serialise a malformed value and not notice until the receiver dies. This is most common with numeric data that has a divide-by-zero or uninitialised-float bug upstream.
undefined. JavaScript will happily emit undefined via console.log; JSON.stringify drops the key entirely. The result is that a property you expected in the payload silently vanishes instead of failing loudly. If the receiver expects the key to exist, you get a downstream null-pointer error rather than a JSON parse error.
Hex and octal literals. 0xff and 0o755 are legal JavaScript but not legal JSON. The grammar is base-10 only. Convert to decimal before emitting.
Unescaped multi-line strings. A literal newline inside a string is invalid; you need \n. Most languages handle this transparently when you build the JSON via their library, but hand-assembled JSON often gets it wrong.
Encoding errors — when "valid JSON" still won't parse
The most-frustrating category, because the document looks right when you open it in a text editor.
The UTF-8 byte-order mark (BOM). Three bytes — 0xEF 0xBB 0xBF — silently prefixed to the start of the file. Windows tooling (Notepad, some Microsoft SDKs, occasionally Out-File in PowerShell) emits one by default. Most editors hide it. Every JSON parser rejects it. Open the file in a hex editor or strip the first three bytes with a script — that's the fix.
Smart quotes. Copy a JSON snippet from Notion, Slack, Word, or any rich-text editor and the double quotes get "helpfully" replaced with curly quotes — “” rather than "". They look almost identical in most fonts. The parser doesn't accept them. The give-away is when the error position is on what looks like a perfectly normal quote character.
Non-UTF-8 input. Windows tooling sometimes emits CP-1252 (also called "Windows-1252") instead of UTF-8. As long as every character in the file is ASCII (under 0x80) the two are byte-compatible and nothing goes wrong. The moment you have a single accented character, an em-dash, or a smart quote, the parser sees an invalid UTF-8 byte sequence and dies. Re-save the file as UTF-8.
Schema vs parse errors — different problem
Worth being precise about this, because the distinction matters for debugging. A parse error is your JSON parser refusing to turn bytes into an object tree — it breaks loudly, at the first invalid byte, before any of your business logic runs. A schema error is a downstream consumer saying "I expected a string here and got a number" — the JSON parsed fine, but the shape is wrong.
Schema errors are quieter and tend to surface deep in the call stack. If you're seeing Expected string, got number or Cannot read property of undefined, you have a schema problem, not a parse problem. JSON Schema validators (Ajv, jsonschema in Python, gojsonschema in Go) catch these at the boundary before they leak into your code.
When the JSON formatter on this site helps
The JSON formatter locates the exact line and column of a parse error — something most language-level error messages get wrong. Its tolerant mode accepts JSONC (comments and trailing commas), so you can paste a tsconfig.json or VS Code settings.json and inspect it visually without first stripping the bits a strict parser would reject. Everything runs in your browser; nothing is uploaded.
Related reading
If you regularly work with large JSON, the best free JSON formatter for large files guide covers what actually matters at 50 MB and up. To compare two JSON files line by line, the text diff checker is the simpler tool. And if your service emits UUIDs as part of the JSON payload, the UUID generator is useful for producing valid sample data when you're building a fixture.