Notes · Sep 5, 2026

The 20 ways a pasted JSON breaks

A document that was JSON when it left a process rarely arrives as JSON. The ways it breaks are few, and they are the same ones every time.

Where broken JSON comes from

Almost never from a JSON serialiser. It comes from a language’s own object syntax — a Python repr, a JavaScript object literal pasted out of a source file, a Ruby hash — from a config dialect that allows comments and trailing commas, from a hand edit that dropped a comma, or from a log line cut at a buffer boundary. Each origin breaks the text in a characteristic way, and each way is one mechanical fix.

broken-webhook-example.json
{
  id: 'evt_1P8xQm2eZvKYlo2C',
  object: "event",
  api_version: "2026-03-20",
  created: 1745247128,
  type: 'payment_intent.succeeded',
  livemode: False,
  data: {
…

The 20 steps, from the engine

These are the repair steps the JSON adapter registers, listed from the engine when this page was built, in the order they run. A step marked as a judgment call can say something your document did not, so it is reported and never applied unless you ask.

  • Strip leading byte-order mark (BOM)
  • Normalise common encoding glitches (mojibake)
  • Escape string values whose content is raw JSON
  • Escape raw newlines and embedded `"` inside string values
  • Split `"key: "value"` into `"key": "value"`
  • Strip `//` and `/* */` comments (not legal JSON)
  • Replace 'single' with "double" quotes
  • Insert missing commas between sibling values
  • Insert missing `:` between property name and value
  • Quote bare identifier keys
  • Remove trailing commas before } or ]
  • Insert `null` for empty value slots in objects/arrays — a judgment call
  • Replace JS/Python literals (True, False, None, NaN, Infinity, undefined) with JSON equivalents — a judgment call
  • Collapse one level of double-escaping — a judgment call
  • Convert literal newlines/tabs in strings into proper JSON escapes
  • Repair broken `\uXXXX` escapes inside string literals
  • Canonicalise non-JSON number literals (leading dot, octal, etc) — a judgment call
  • Quote bare identifier values (`production` → `"production"`)
  • Insert missing close brackets when an array/object closes with the wrong glyph — a judgment call
  • Drop content after the document root — reported, applied only when asked

What that looks like on one file

The webhook sample above — a Stripe event printed from Python and edited by hand — needs 46 fixes in 7 kinds: 31 × quote unquoted key, 7 × remove trailing comma, 3 × single → double quotes, 2 × python false → json false, 1 × insert missing comma after value, 1 × python true → json true, 1 × python none → json null. Fix all applies them, greens the lines it touched, and leaves every other byte as pasted; Undo puts the original back exactly.

What no step does: guess at content. A value that is missing stays missing and is listed as a problem with its line. Fixing syntax is mechanical; inventing data is not, and the list is where the two are kept apart.

Try it

Try it on the file that broke your afternoon.

free while in alpha · no signup