Someone copies a JSON blob into a JSON validator, gets an error, and assumes the JSON is broken. Most of the time, the JSON is fine. The problem is invisible characters copied from a terminal, trailing commas that JavaScript allows but JSON doesn't, or serialization edge cases that strip data silently.
Invisible Characters in JSON
When you copy JSON from a terminal or email, you pick up invisible characters most JSON validators won't show you:
| Character | Looks like | What it breaks |
|---|---|---|
| Zero-width space (U+200B) | Nothing | Key names with invisible gaps |
| Non-breaking space (U+00A0) | Regular space | Parser sees unexpected token |
| Tab (U+0009) | Spaces if you're lucky | Indentation errors |
| UTF-8 BOM (U+FEFF) | Nothing | First key gets a hidden prefix |
| En dash (U+2013) | Hyphen | Number parsing fails |
A team spent hours debugging a 400 error from an API. The JSON payload validated correctly in three different tools. The problem was invisible newline characters embedded in a key name, picked up from copying the JSON from a terminal with wrapped lines. The validator said "unexpected token at position 347" and left them guessing. It never showed them the actual bytes at that position.
The UTF-8 BOM (U+FEFF) is a common offender. Some editors and terminals add it silently. Your first key ends up with an invisible prefix that parsers can't handle. Validators rarely flag it with a useful message.
The JSON Validator on this site detects invisible characters and shows the exact byte at the error position.
Trailing Commas
JSON does not allow trailing commas. JavaScript objects do. This mismatch causes a specific, predictable failure: you write JSON in a .js or .ts file where trailing commas work fine, then move it to a .json file or send it over HTTP, and suddenly it breaks.
{
"name": "John",
"age": 30,
}
That comma after 30 is invalid. Your brain tells you "but this worked five seconds ago" and you waste time figuring out why. The same applies to arrays. A trailing comma after the last element fails identically.
The JSON spec (RFC 8259) is unambiguous: no trailing commas, ever. But some API gateways and HTTP proxies strip trailing commas before forwarding the payload. This masks the problem during local development and only surfaces it when requests reach a backend with stricter parsing. If you've ever had a request that works in Postman but fails in production, trailing commas are a plausible culprit.
NaN, Infinity, and undefined Get Silently Stripped
JSON has no concept of NaN, Infinity, or undefined. How JavaScript handles them during serialization depends on the type:
const data = {
score: NaN,
max: Infinity,
name: "test",
removed: undefined
};
JSON.stringify(data);
// Result: {"score":null,"max":null,"name":"test"}
NaN and Infinity become null. The key isn't dropped; the value is replaced. Only undefined values cause keys to disappear from the output entirely. An API endpoint that calculates a division producing NaN doesn't lose the field; it sends null instead. The client receives something, but it's not what anyone intended.
This is the kind of bug that lives in production for weeks because test data never triggers the edge case. The API looks fine in staging, and under real traffic a specific calculation silently starts producing null values.
The real challenge is that different languages handle these edge values inconsistently:
| Language | NaN | Infinity | undefined / None |
|---|---|---|---|
| JavaScript (JSON.stringify) | Becomes null | Becomes null | Key dropped in objects |
| Python (json.dumps, default) | Raises ValueError | Raises ValueError | Raises TypeError |
| Python (json.dumps, allow_nan=True) | Writes NaN (invalid JSON) | Writes Infinity (invalid JSON) | Raises TypeError |
| Go (encoding/json) | Returns error at serialize time | Returns error at serialize time | Returns error at serialize time |
| Java (Jackson) | Throws exception by default | Throws exception by default | Skipped by default |
A value that serializes fine in one service breaks when consumed by another. The error message rarely points to the root cause; it shows up as a generic parsing failure on the receiving end.
Single Quotes
JSON requires double quotes for strings. Not single quotes, not backticks.
// Not valid:
{ 'name': 'value' }
// Valid:
{ "name": "value" }
JavaScript runtimes parse single-quoted "JSON" fine because it's actually a JavaScript object literal. But when you send it to an API or write it to a .json file, it fails. Most JSON validators will tell you it's wrong but not why. The error position points to the first single quote, but the real issue is that you're writing JavaScript syntax in a JSON context.
Next time a validator says "unexpected token" and you can't see why, paste it into the JSON Validator and check for invisible characters first. That's the case that wastes the most time by far.