Fix Invalid JSON: How to Repair Trailing Commas, Single Quotes, and Broken LLM Output
A strict JSON parser rejects the whole document over one stray comma. That is correct behavior, and it is also why you are here: you have a payload that is almost JSON and a SyntaxError that tells you nothing useful about how to make it parse.
This guide is about repair, specifically. Not formatting, not validation. Repair is a best-effort, sometimes-lossy transform that takes input written in JSON-adjacent dialects, or output a model truncated mid-stream, and rebuilds a structure a strict parser will accept. It guesses. Good repair tells you what it guessed so you can decide whether the guess was right.
The fastest way to run any of this is the browser-based JSON Repair tool, which applies these fixes and lists every change it made. The rest of this page explains what is actually happening under each fix, where repair stops being safe, and how to keep it separate from the two jobs people constantly confuse it with.
Repair is not formatting, and it is not validation
These three operations get lumped together because they all touch JSON and live next to each other in a toolbar. They do completely different things, and confusing them costs you debugging time.
| Operation | Input assumption | What it does | Can it change meaning? |
|---|---|---|---|
| Format / prettify | Already valid JSON | Re-indents, sorts, minifies | No |
| Validate | Maybe valid, maybe not | Pass/fail plus error location | No (read-only) |
| Repair | Invalid, but close | Rewrites to make it parse | Yes, sometimes |
A formatter will refuse your broken input outright, because it parses strictly first and pretty-prints second. If your JSON is already valid and you just want it readable, reach for the JSON Formatter instead and skip repair entirely.
Validation is the opposite end. When you need a hard yes/no on whether a string is RFC 8259 JSON, use a strict validator. It will never touch your data. It just tells you, with a line and column, exactly where the parser gave up.
Repair sits in the uncomfortable middle. It assumes the input is broken and tries to fix it anyway. That is the only one of the three that can silently alter what your data means, which is why the rest of this guide spends so much time on what gets changed.
The mechanical fixes: trailing commas, single quotes, unquoted keys
The most common breakage is not exotic. It is JavaScript object-literal syntax that someone pasted expecting JSON to be just as forgiving. JSON is not. But the fixes here are mechanical and lossless, meaning the repaired output means exactly what you intended.
Trailing commas. Legal in modern JavaScript object and array literals, and in JSON5. Illegal in JSON. The fix is to drop the comma before a closing } or ]:
{ "tags": ["a", "b",], } → { "tags": ["a", "b"] }This never changes meaning. The trailing comma carried no value; removing it is pure cleanup.
Single quotes and backticks. JSON strings must use double quotes. JavaScript happily uses single quotes or template-literal backticks, and a lot of pasted config does too. Repair re-quotes them:
{ name: 'Ada', role: `lead` } → { "name": "Ada", "role": "lead" }This is safe as long as the string contents do not themselves contain an unescaped double quote, in which case the repairer has to escape it. Watch for apostrophes inside single-quoted strings ('it\'s fine') because that is where naive find-and-replace approaches break and a real lenient parser does not.
Unquoted keys. JavaScript lets you write { name: "Ada" }. JSON demands { "name": "Ada" }. The repairer quotes the bare identifier. Lossless, again, because the key's identity is unchanged.
All three of these are the same underlying story: the data came from a place where JSON's rules are relaxed. The structure is sound. You are just translating dialects.
Language literals: Python None, smart quotes, and the NaN problem
The next tier is messier because it crosses language boundaries. The classic source is someone copying the output of a Python print() or a logged dict straight into a JSON field.
Python literals. Python writes None, True, and False where JSON writes null, true, and false. The mapping is unambiguous and lossless:
{ 'active': True, 'parent': None } → { "active": true, "parent": null }Smart quotes and code fences. Text that passed through a word processor, a chat app, or a Markdown renderer arrives with curly quotes (“ ”) instead of straight ones, or wrapped in a ```json fence. Repair normalizes the quotes and strips the fence. Cosmetic damage, clean fix.
NaN and Infinity, where repair turns lossy. JSON has no way to represent NaN, Infinity, or -Infinity. The spec simply does not include them. JavaScript's own JSON.stringify emits them as null, and a repairer has to do the same:
{ "ratio": NaN, "cap": Infinity } → { "ratio": null, "cap": null }That is a genuine loss of information. NaN and Infinity are distinct values, and after repair they are both indistinguishable null. If those numbers carry meaning in your pipeline, repair is the wrong tool and you need to fix the producer to emit a sentinel you control, like a string "Infinity" or a flag field. A trustworthy repairer flags this conversion explicitly rather than burying it, because it is exactly the kind of change that breaks downstream math without throwing an error.
Repairing broken LLM output: comments, prose, and truncation
Models are now a major source of nearly-JSON. You ask for JSON, you get JSON wrapped in three layers of helpfulness. The repair patterns here are worth knowing because they are predictable.
- Code-fence wrappers. Output arrives as
```json\n{...}\n```. Strip the fence, keep the body. - Leading prose. “Here is the JSON you requested:” before the object, or a trailing “Let me know if you need changes.” Repair locates the actual JSON span and discards the chatter.
- Inline comments. Models love annotating fields with
// like thisor/* this */. JSON forbids comments; repair removes them. If you specifically want comment-stripping without the rest of the repair machinery, the JSON comments stripper does just that, and JSONC to JSON handles the commented-config case. - Anti-hijacking prefixes. Some APIs prepend a guard like
)]}'to defeat JSON hijacking. Repair recognizes and drops it.
The hard one is truncation. A model hits its output token limit and stops mid-structure, leaving you with an unterminated string and a stack of unclosed brackets:
{ "items": [ { "id": 1, "name": "widRepair can close the open string at the break and balance the brackets, producing { "items": [ { "id": 1, "name": "wid" } ] }. That parses. But the last value is a half-word, and any items the model never got to are simply gone. This is recovery, not reconstruction. Treat a repaired truncation as a damaged record to be re-fetched, not a clean one to be trusted.
The durable fix for truncation is upstream: raise max_tokens, or request a smaller schema. If you are routinely hitting the ceiling, measure your prompt and expected output against the model's window with a token counter before you blame the parser. Repair patches the symptom; the budget is the disease.
When repair is the wrong move
Repair is a convenience for humans looking at a payload, and a fragile crutch in a production hot path. Know the difference.
Do not silently repair untrusted data in production. If an upstream service or a model is feeding you invalid JSON, that is a signal. Auto-repairing it hides a real integration bug and can mask a partial or corrupted response as a complete one. Log it, alert on it, then decide. Repair on read, never on the assumption that the data was fine.
Do not repair when the breakage is structural and ambiguous. Two unkeyed values jammed together, or brackets that mismatch with no clear nesting, have no single correct interpretation. A good repairer refuses these rather than inventing a structure. If a tool confidently “fixes” genuinely ambiguous input, distrust it more, not less.
Do not use repair as a substitute for JSON5 when you control the source. If the input is intentionally JSON5, with comments, trailing commas, and unquoted keys by design, and you own it, convert it once with JSON5 to JSON and store the strict result. Repair is for accidental breakage, not for a format you chose on purpose.
The honest framing: repair gets you from “this won't parse” to “this parses, and here is everything I changed” in one paste. That is enormously useful when you are debugging a payload late at night. It is not a guarantee that the data is correct, only that it is now syntactically legal.
A practical repair workflow
Here is the sequence that keeps you out of trouble.
- Validate first. Run the raw input through a strict validator. If it passes, you do not have a repair problem, you have a formatting preference. Stop here.
- Repair. Paste the failing input into the JSON Repair tool and read the list of fixes it reports. The fix list is the product; the repaired JSON is secondary.
- Audit the lossy fixes. Scan the report for anything that changed meaning:
NaN/Infinitytonull, a closed unterminated string, an inferred missing comma. Those are the lines to eyeball. - Inspect the result. For anything non-trivial, drop the output into a JSON tree viewer to confirm the structure matches what you expected, especially around any truncation point.
- Fix the source. If the same break keeps recurring, the repair tool is not the answer. A producer emitting Python literals, a model truncating output, or a config that should have been JSON5 from the start each has a root cause. Repair buys you time to fix it properly.
Everything above runs client-side in the browser, so you can repair payloads containing tokens, keys, or customer data without it leaving your machine. That matters specifically here, because the JSON most worth repairing tends to be the JSON you cannot paste into a random web service.
Skip the manual work. The companion tool runs this in your browser, with nothing uploaded.
JSON RepairFrequently asked questions
What is the difference between repairing and validating JSON?
Validation is read-only: it tells you whether a string is valid JSON and, if not, where it breaks. Repair rewrites the input to make it parse, which means it can change your data, for example turning NaN into null. Validate to diagnose; repair to fix. Use a strict validator when you only need a yes/no answer.
Does repairing JSON ever change the meaning of my data?
Most fixes are lossless: removing a trailing comma, quoting bare keys, or converting Python None to null preserve meaning exactly. A few are lossy by necessity. NaN and Infinity become null because JSON cannot represent them, and an unterminated string gets closed at the break point. A good repairer lists these changes so you can verify each one.
Can it fix JSON that an LLM truncated mid-output?
Partially. It can close the unterminated string and balance the open brackets so the result parses, but any content the model never produced is gone. Treat a repaired truncation as a damaged record, not a complete one. The real fix is raising the output token limit or requesting a smaller schema so the model finishes.
Is repairing JSON the same as converting JSON5?
No. JSON5 is a deliberate format with comments, trailing commas, and unquoted keys, and you convert it once when you own the source. Repair is for accidental breakage from any source, including JavaScript literals, Python output, and LLM responses. Repair accepts JSON5-style input but its job is recovery, not format conversion.
Should I auto-repair JSON in my production pipeline?
Be careful. Invalid JSON from an upstream service or model is usually a signal worth logging and alerting on, not silently patching. Auto-repair can mask a partial or corrupted response as a clean one. Repair is excellent for debugging a payload by hand; in production, fix the producer instead of hiding the symptom.
Is my data sent to a server when I repair it?
No. The JSON Repair tool parses and rewrites entirely in your browser with client-side JavaScript. Nothing is uploaded, so you can safely repair payloads that contain API keys, tokens, or private customer data.