JSON Repair

Fix broken JSON — trailing commas, // and /* */ comments, single quotes, unquoted keys and Python's True/False/None — then pretty-print the result.

In your own code: JSON5.parse from the json5 package on npm reads comments, single quotes, unquoted keys and trailing commas. The other mends here — missing commas, Python words, bare words, cut-off input — are this page’s own pass on top of it.

What is JSON Repair?

JSON Repair takes malformed or near-JSON text and rewrites it as strict, valid, pretty-printed JSON. It fixes the breakages people paste every day: trailing commas, // line and /* block */ comments, single-quoted strings, unquoted keys, and raw JavaScript object literals — and past those, a missing comma between members, a bare word where a value goes, Python’s True, False and None and JavaScript’s undefined, and a raw line break or tab inside a string. Under the result, “What was changed” lists each mend it made, with the line and column where it sits in the text as you pasted it.

How is it different from a JSON formatter?

A formatter assumes your input is already valid and only re-indents it. JSON Repair assumes the input is broken and recovers it first, then formats — so it succeeds on the messy JSON you get from logs, config files, and LLM chat responses.

What is not JSON, and why your file has it anyway

JSON is a much smaller language than it looks. Keys must be double-quoted strings; there are no trailing commas, no comments, no single quotes, no NaN or Infinity, no hex numbers, no leading +, and no undefined. Every one of those is legal in a JavaScript object literal, which is why text copied out of a source file, a console or a config so often fails to parse — it was never JSON, it was JavaScript that resembles it. Python adds its own near-misses: True, False and None.

Repair is a guess, and some guesses are dangerous

Fixing quotes and dropping trailing commas is safe: the intent is unambiguous. Closing an unclosed bracket is not — a file truncated mid-transfer is missing content, and adding a } produces something that parses while quietly meaning less than the original did. That is why a cut-off input is refused unless you tick “Close what the input left open”, and why the result then says that whatever was cut off is not in it. Numbers are the sharpest edge: JSON has one number type and parsers read it as a double, so an ID beyond 2⁵³ loses its last digits before any repair has a chance to run. If the values matter, always diff the repaired output against the source rather than trusting that a parse means a correct read.

Frequently asked questions

What kinds of broken JSON can it fix?

Trailing commas, // line and /* block */ comments, single-quoted strings, unquoted or JavaScript-style keys, and full JS object literals — plus missing commas between members, unquoted values, True, False, None and undefined, and raw line breaks inside strings. It also strips ```json code fences so you can paste output straight from an LLM chat.

Why does my JSON with comments fail?

Because JSON has no comments — neither // nor /* */. What you have is JSONC or JSON5, which several tools accept and the standard parser does not.

Can it recover a truncated file?

Only if you ask. By default a cut-off file is refused with the line and column where reading stopped, because adding the missing brackets gives JSON that parses while meaning less than the original. Tick “Close what the input left open” and it closes the open string, lists and objects — a key whose value was cut off gets null — and warns that whatever was cut off is not in the result. If you can, go back for the whole file.

My large numbers changed. Why?

JSON has a single number type and parsers read it as a 64-bit float, which holds integers exactly only up to 2^53. Longer IDs lose their tail. The fix is on the producing side: send them as strings.

Can it put back a missing comma or quote a bare value?

Yes, where there is only one reading. A comma goes back only where one value has visibly ended and the next member or element starts — {"a": 1 "b": 2} or [1 2 3] — and a bare word where a value goes becomes a string that runs to the end of its line, so {name: Al Smith} keeps "Al Smith" whole. Python’s True, False and None and JavaScript’s undefined become true, false and null outside strings, and a raw line break inside a string is written as \n. What has two readings, such as {"a": 1 2} or two documents one after the other, is still refused rather than guessed at.

Can I see exactly what the repair changed, and do the same in my own code?

Yes. Under the repaired JSON, “What was changed” lists each fix with its line and column in the text as pasted — a removed comment, a quoted key, an added comma, a Python word replaced — and names a repeated key, whose later value is the one kept; input that was JSON already is said to need no mending. A line under the tool names JSON5.parse from the json5 package on npm as what reads comments, single quotes, unquoted keys and trailing commas; the other mends are this page’s own pass.