Common JSON errors and how to fix them
JSON is the format many APIs, configuration files and web apps use to exchange data, and its grammar fits on a single page. That is also why it is unforgiving: a text is either valid JSON or it is not, and one stray comma is enough for a parser to reject the whole thing. Most errors come from the same few habits, many of them carried over from JavaScript or other languages. This guide lists the rules, the mistakes that break them most often, how to read the error message, and a few cases that are valid JSON but still cause problems.
The rules JSON actually has
The current definitions are RFC 8259, published in December 2017, and ECMA-404. They describe the same syntax:
- Strings, including every property name, use double quotes. Single quotes are not allowed.
- Values are strings, numbers, objects, arrays or one of three literals: true, false and null, always in lower case.
- Items in objects and arrays are separated by commas, with no comma after the last one.
- Numbers are written in decimal, with no leading zeros, no plus sign and no NaN or Infinity.
- Inside a string, the double quote, the backslash and control characters such as a line break must be escaped.
- There is no syntax for comments.
Between tokens, only four whitespace characters are allowed: space, tab, line feed and carriage return.
The most common errors
Each of these is rejected by a standard parser. The fix is in the description.
{"name": "Ana",}Trailing comma: remove the comma after the last item of an object or array.{'name': 'Ana'}Single quotes: use double quotes for property names and strings.{name: "Ana"}Unquoted property name: every name must be a string in double quotes.{"a": 1 "b": 2}Missing comma between two items, often after lines are copied together.{“name”: “Ana”}Typographic quotes, which word processors and chat apps insert automatically: replace them with straight " quotes.{"note": 1 // total}Comments are not part of JSON: remove them, or move the note into a property.{"active": True}Capitalised literals: write true, false and null in lower case.{"value": undefined}undefined, NaN and Infinity exist in JavaScript but not in JSON: use null or a string.{"code": 007}Leading zeros are not allowed in numbers: write 7, or "007" as a string if the zeros matter.{"path": "C:\Users"}A single backslash starts an escape sequence, and \U is not one. Worse, C:\new would be accepted and read as C:, a line break and ew. Write \\ for a literal backslash.{"items": [1, 2}A bracket that is never closed or closed with the wrong character: every { needs a } and every [ needs a ].
Reading the error message
A parser reads the text from left to right and stops at the first character it cannot accept, so the position in the error message is where it gave up, which is often just after the actual mistake. With a trailing comma, the parser complains about the closing brace, because after a comma it expects another property name. With a missing bracket, the error may appear at the very end of the text, far from where the bracket should have been.
The wording differs between browsers and languages, and many messages give a position, though not all, either as a character count from the start or as a line and column. For example, Chrome's JavaScript engine reports {"name":"Ana",} as:
Expected double-quoted property name in JSON at position 14 (line 1 column 15)Counting from 0, position 14 is the closing brace; the comma that caused the error is one character earlier.
When the position is not obvious, look at the character just before it, and check that every opening bracket and quote before that point has its partner. An editor that highlights matching brackets often makes a missing one easy to spot.
Valid JSON that still causes trouble
- Large numbers. JSON itself sets no limit, but JavaScript, and many JSON parsers in other languages, store numbers as 64-bit floating point, which guarantees exact integers only up to 9,007,199,254,740,991. In JavaScript, JSON.parse turns 9007199254740993 into 9007199254740992 without any warning. Large IDs are safer as strings.
- Duplicate property names. RFC 8259 says names should be unique and that software receiving duplicates behaves unpredictably. JavaScript keeps the last value: {"a": 1, "a": 2} becomes {"a": 2}.
- A byte order mark. Some editors save UTF-8 files with an invisible U+FEFF character at the start. RFC 8259 forbids adding it to JSON sent over a network, and JavaScript's JSON.parse rejects text that starts with it.
- A bare value at the top level. Current standards (ECMA-404, and RFC 7159 from 2014 onwards) allow a JSON text to be any value, such as "hello" or 42, but the earlier RFC 4627 from 2006 required an object or an array, and some older parsers still do.
JSON is not JavaScript
JSON's syntax was taken from JavaScript object literals, which is why the two are so easily confused. A JavaScript object literal accepts single quotes, unquoted names, trailing commas, comments and values such as undefined; JSON accepts none of them. Code that works when pasted into a script can therefore fail as a JSON file.
Some tools accept extended formats such as JSON5, or “JSON with comments” for configuration files. They are convenient where they are supported, but they are not JSON, and a standard parser, including the nTools formatter, will reject them.
Frequently asked questions
Can JSON have comments?
No. The specification has no comment syntax. If you need notes in the data, put them in a property such as "_comment", or use a format that allows comments where the tools support it.
Why does my JSON work in JavaScript but fail in a validator?
Because a JavaScript object literal allows things JSON does not, such as single quotes, trailing commas and unquoted names. Pasted into code it runs; saved as JSON it is invalid.
How do I keep a very large number exact?
Send it as a string, for example "9007199254740993", and convert it on the receiving side with a type that can hold it, such as BigInt in JavaScript.
Does the nTools formatter send my JSON anywhere?
No. It is parsed and formatted in your browser, and when the browser reports a position, the formatter shows it as a line and column.
Related guides
- IP addresses explained: IPv4, IPv6 and the reserved ranges
- Subnets and CIDR explained: prefixes, masks and usable hosts
- DNS records explained: A, AAAA, CNAME, MX, TXT and NS
- Unix timestamps and time zones explained
- Image formats explained: JPEG, PNG, WebP, AVIF and HEIC
- Password strength explained: length, entropy and passphrases
- UUIDs explained: v4, v7 and choosing the right version
- QR codes explained: capacity, error correction and print size
- Percentages and VAT explained: adding, removing and stacking
- Editing PDFs in the browser: what merging, splitting and converting keep