What counts as valid JSON
JSON is a much stricter format than the JavaScript it came from. The rules that catch people out:
- Double quotes only. Both keys and text values need them.
'name'andnameare both rejected; only"name"is valid. - No trailing commas. The comma in
[1, 2, ]is an error, even though your editor may accept it elsewhere. - No comments. There’s no way to write one in standard JSON.
- Numbers are plain. No
NaN, noInfinity, no leading+, no hex, no trailing dot.01is invalid too. undefineddoesn’t exist. Usenull.- Any value can sit at the top level. An object is usual, but a bare array, string, number,
true,falseornullis also valid JSON.
Errors and what they usually mean
| What you’ll see | What’s usually wrong |
|---|---|
| Expected a key in double quotes, with a trailing-comma note | A comma sits before the closing }. |
| Expected a key in double quotes: single quotes and bare words aren’t valid | 'name' or name where "name" is needed. |
| Two values need a comma between them, or a bracket is left open | A missing comma between items, or a copy-paste that stopped short. |
| The JSON ends too early | The text runs out mid-value: a brace, bracket or quote is never closed. |
| There’s extra text after the JSON value ends | A second object pasted after the first, or a stray character at the end. |
The line and column we show point at the character the parser choked on, which is where it gave up rather than where you slipped.
Escaped JSON, and how to get rid of it
JSON has no problem carrying JSON inside itself, but only as text, with every quote escaped. It turns up constantly:
- a log line that records a request body as one string
- a webhook whose
bodyormessagefield holds the real payload - a queue message, where the useful part is
Messageinside the envelope - a database column that stores JSON as a string
The result is unreadable, and the backslashes multiply every time it’s wrapped again:
| Level | What you see |
|---|---|
| The data | {"orderId":123} |
| Escaped once | "{\"orderId\":123}" |
| Escaped twice | "\"{\\\"orderId\\\":123}\"" |
Unescape peels those layers off, up to five of them, and tells you how many it removed. It works whether or not the value still has its surrounding quotes, so a fragment copied out of the middle of a log line is fine.
Expand JSON inside strings is for the other shape: a normal document where only some fields hold escaped JSON. Tick it in Format mode, and each of those fields is parsed in place, so the whole payload reads as one document.
Escape does the reverse, turning a document into a single string with the quotes and line breaks escaped, ready to paste into another payload or a test fixture.
Sorting keys makes two payloads comparable
Tick Sort keys A–Z and every object is rewritten in alphabetical order, at every level. This is the quickest way to compare two API responses that contain the same data in a different order: sort both, then diff them. It changes only the order of keys, never their values.
Large numbers lose precision
JSON numbers are parsed as standard floating-point values, which hold about 15–17 significant digits. A 20-digit ID, like a Twitter or Discord snowflake, comes back slightly wrong, and formatting writes the wrong value back out. This isn’t a quirk of this page: JSON.parse behaves the same way in Node and in every browser.
If your data has IDs that long, they should travel as strings ("1234567890123456789"), which survive untouched.
Minify or pretty-print
Pretty-printing is for reading and for diffs: one value per line, indented by nesting. Tabs suit teams who want everyone to control their own indent width; 2 spaces is the common default.
Minifying strips every space and line break. It’s for sending data over the network or pasting into an environment variable, not for storing in a repository, where a one-line file makes code review painful.