Home Developer & Utility Tools Guide

How to fix "JSON parse error" messages

A field guide indexed by error message: "Unexpected token N", "Unexpected end of input", "Unexpected token < in JSON at position 0" — what each means, and the actual fix.

Your service just crashed because a JSON payload didn't parse. The stack trace points at a parser call. The error message looks like the parser was halfway through writing the alphabet when it gave up: Unexpected token < in JSON at position 0. What does that actually mean, and which way do you fix it?

This page is the lookup table. Each section is keyed on the message a strict JSON parser (Node, Python's json, Go's encoding/json) produces. The fixes are ordered roughly by how often you'll hit each problem in production.

"Unexpected token < in JSON at position 0"

The single most common JSON parse error in modern web applications. The fact that the offending character is < at position zero is the whole story: the response started with an HTML tag.

You expected JSON. You got HTML. The backend returned an error page — a 404 from an Nginx default config, a 500 with a framework debug page, a Cloudflare challenge page, an auth-redirect login screen — and the client tried to parse it anyway. Every HTML document starts with <!DOCTYPE html> or <html>, hence the < at position 0.

The fix is on the client side, not the parser side. Log the response body and status code before parsing. Treat any status of 400 or above as do not parse; surface the body as text for the developer to look at. If the backend should always return JSON, check the Content-Type header — anything that isn't application/json is an error, regardless of what the status code says.

"Unexpected token N in JSON" (or I, or u)

Three closely related cases:

  • N at the start of a value — the producer wrote NaN.
  • I at the start of a value — the producer wrote Infinity or -Infinity.
  • u at the start of a value — the producer wrote undefined.

JavaScript permits all three as values, JSON does not. The JSON spec has no representation for non-finite numbers or for undefined. A producer that hand-rolled its serialiser, or one that called JSON.stringify on a value containing NaN without checking, will write these out and break every downstream parser.

JSON.stringify has uneven behaviour worth knowing: it converts undefined to null inside arrays and silently drops it inside objects. But for NaN and Infinity, it writes them out as literals that no strict parser will accept.

The fix is at the producer. Before serialising, replace NaN and Infinity with null or with a sentinel string. If the producer is JS, walk the object before JSON.stringify and clean it. If you're consuming someone else's broken JSON and can't change them, use a tolerant parser as a one-shot fallback — this site's JSON formatter tolerates NaN and Infinity on a best-effort basis.

"Unexpected token } in JSON at position X"

A trailing comma. {"a": 1, "b": 2,} is valid JavaScript object syntax and invalid JSON. The comma after the last value tells a strict parser to expect another key-value pair; finding } instead, it gives up.

The same problem appears with arrays: [1, 2, 3,] fails with Unexpected token ]. The fix is to remove the trailing comma. If the JSON is generated by hand or by string concatenation, this is almost always where the bug is. The reliable fix at the producer is to use JSON.stringify (or the equivalent in your language) instead of building the string by hand.

JSONC, JSON5, and many editor configs allow trailing commas as an extension. If your input comes from one of those formats, you need a tolerant parser, not a strict one — the file isn't really JSON.

"Unexpected end of input"

The parser reached the end of the document before finding the closing bracket or brace it was expecting. The payload was truncated.

Causes, in rough order of likelihood:

  • The producer crashed mid-write. The first half of the response went out, then the process died.
  • A reverse proxy or load balancer timed out the connection mid-stream. The response advertised one Content-Length and delivered less.
  • A streaming or chunked-encoding bug where the 0\r\n\r\n terminator never arrived.
  • A read on the client side that stopped at the wrong place — too small a buffer, an early return from a stream handler.

Check the producer first (did it finish writing the response?), then the transport (any proxies in the path with their own timeouts?), then the client read logic. The parse error is the symptom; the broken transport is the cause.

"Unexpected token ' in JSON"

Single quotes. JSON's grammar requires double quotes around all strings and all keys. JavaScript object literals accept either; copy-paste from a JS file into a JSON file is the usual route to this error.

The fix at the producer is to switch to double quotes — or, again, use JSON.stringify and let the language emit them correctly. If you're consuming a fixed source with single quotes, a tolerant parser (or a quick regex pass replacing single with double quotes) is the pragmatic option, with the caveat that it'll break on strings that legitimately contain apostrophes.

"Invalid character" or weird bytes at position 0

UTF-8 byte-order mark. The three bytes 0xEF 0xBB 0xBF at the start of a file are the BOM — a marker that some Windows editors add by default to identify the encoding. JSON has no BOM concept; a strict parser sees three garbage bytes before the opening { and refuses to proceed.

The fix is to save the file without a BOM. VS Code, Sublime, Notepad++ — all of them have an "Encoding: UTF-8 without BOM" option. In code, strip the first three bytes if they match the BOM signature before passing to the parser.

Schema errors are not parse errors

One distinction worth carrying around. "Expected string, got number" is not a parse error. The parser succeeded — it returned a valid JSON value. A downstream validator (Ajv, JSON Schema, your own type checks) then rejected the value as the wrong shape.

Parse errors die at byte zero of the response, before your application has any structured value to work with. Schema errors die later, when something tries to use a field that doesn't match the contract. The fix in each case lives in a different layer: parse errors are usually a producer or transport problem; schema errors are usually a producer-consumer agreement problem.

Practical takeaways

  • Log the actual response body before calling JSON.parse (or equivalent). Most of the errors above are obvious from one look at the raw text.
  • Use a strict JSON formatter — like the one on this site — to locate the exact line and column the strict parser tripped on. Eyeballing a 500-line payload is a non-starter.
  • Treat any non-2xx HTTP status as a signal to skip the parse and surface the body for debugging. The Unexpected token < problem disappears the moment you do this.

Related reading

The JSON parse errors field guide goes deeper into the edge cases and tolerant-parser strategies. The large-files guide covers what changes when the JSON itself is megabytes rather than kilobytes. The JSON formatter and text diff checker are the two tools you'll reach for most often when something doesn't parse.