Unexpected token X in JSON at position N is what JSON.parse throws the moment it hits a character it can’t make sense of, given where it is in the document. It’s accurate but not useful on its own - it tells you a byte offset, not what’s actually wrong or how to fix it. This is especially common with JSON pasted from Claude, GPT, or another LLM, since the underlying text often isn’t strict JSON to begin with. This post walks through what the error means and the specific characters that tend to trigger it.
What the error is actually telling you
A JSON parser reads character by character, tracking what kind of value it expects next based on where it is in the structure - an object expects a key or a closing brace, an array expects a value or a closing bracket, and so on. “Unexpected token” means the parser hit a character that’s not valid in that position. The token named in the error (a comma, a quote, a letter) and the position are your two clues - and in JSON.parse’s case, usually the only two you get.
The usual suspects, in order of how often they show up
A stray backtick or code fence. If the JSON is still wrapped in a ```json fence from a chat response, the first backtick itself is often the “unexpected token,” since it appears at position 0, before any valid JSON value starts.
Unexpected token '<' - almost always means you accidentally captured an HTML error page instead of the JSON you expected, usually from a failed API request that returned a 404 or 500 page instead of a JSON body.
Unexpected token u - typically undefined written literally into the output instead of null. JSON has no undefined - only null - and undefined isn’t a string here, it’s an unquoted word the parser doesn’t recognize as a value.
Unexpected token ' - a single-quoted string. JSON strings are always double-quoted; a model that leans on JavaScript or Python conventions will sometimes use single quotes instead.
Unexpected token , - almost always a trailing comma before a closing } or ]. Valid in a JavaScript object literal, invalid in JSON.
Unexpected end of JSON input - a close cousin of the above errors, not quite the same message, but worth knowing: it means the document ended before the parser found a matching closing bracket, which is the signature of a truncated LLM response that got cut off mid-object.
A literal newline inside a string. JSON string values can’t contain a raw line break - it has to be escaped as \n. If a model’s output includes a multi-line string with real newlines instead of the escaped form, the parser hits the line break unexpectedly, inside what it thought was still a string.
Locating the exact spot
JSON.parse’s position number counts characters from the very start of the string, which is not the same as counting lines - not something you can eyeball on anything longer than a short snippet. Paste the same text into Jsontify instead: the status bar and error banner report the actual line and column, and a “Go to error” button jumps the raw editor straight to the character in question, which is far faster than counting through a wall of text by hand.
Fixing it
Once you’ve confirmed which pattern above you’re looking at, the fastest fix is usually not to fix it by hand at all. Jsontify’s Repair tool runs a dedicated pass that handles every pattern in this list automatically - stray code fences, single quotes, trailing commas, unquoted literals, and a best-effort close for a truncated document - and replaces the document with a valid version in a single undoable step. If you only have one small issue and would rather fix it yourself, the line and column from the validator is usually enough to spot and correct it directly in the raw pane.
Either way, this happens entirely in your browser: parsing, validating, and repairing all run in a background worker - nothing is uploaded to our servers, so pasting a real API response or a chunk of production log data to debug it doesn’t mean sending that data anywhere else first.
A quick mental checklist
Next time JSON.parse throws “Unexpected token,” it’s worth running through this list in order before assuming the data itself is unrecoverable:
- Is there a code fence or extra text around the JSON?
- Is the reported token a
<- did you actually get an error page back instead of JSON? - Is it
undefined, a single quote, or a trailing comma - one of the classic LLM-output habits? - Does the error say “Unexpected end of input” - is the response simply cut off?
Most of the time, the answer is one of these four, and Repair fixes it in the time it takes to click the button.