What breaks JSON in practice
LLM output is the top source of broken JSON today. Models wrap answers in ```json fences, put a sentence of prose before the payload, and stop mid-token at an output limit. The object inside is often fine; the wrapper and the missing tail are what make JSON.parse throw "Unexpected token" at position 0 or "Unterminated string" at the end.
Python is the second source. print(payload) and logging a dict both emit repr() syntax: single quotes plus True, False, and None with capital letters. json.dumps() would have produced valid JSON, but once the text sits in a log file that option is gone.
JavaScript object literals fail for a different reason. Source code and console output allow bare keys, // comments, trailing commas, undefined, NaN, and Infinity. All of that is valid JavaScript and none of it is valid JSON, which surprises you the first time you paste a config object into a parser.
The rest is transport damage: word processors swap straight quotes for curly ones, a payload gets copied together with the sentence introducing it, or log rotation cuts a line in half. Each of these breaks in a predictable way, which is why a deterministic repairer can fix them.