Trailing Comma in JSON: Two Different Errors, and Only One Tells You Where
Deleting the comma is the easy part. Finding it is not, because the error you get depends on whether the comma is in an object or an array — and only one of those two tells you where to look.
The short answer
JSON has no allowance for a comma after the last item. A comma separates values; it does not terminate them. Remove it and the document parses.
The part worth knowing is that current V8 does not report the two cases the same way. A trailing comma in an object produces an error with a position, line, and column. The same mistake in an arrayproduces a message with no location at all — so the standard advice to “look at the reported line” only works half the time.
The two cases
Identical mistake, two different messages:
{"a": 1,} -> {"a": 1}
[1, 2,] -> [1, 2]| Input | Where | V8 13.6 | Located? |
|---|---|---|---|
| {"a": 1,} | Object | Expected double-quoted property name in JSON at position 8 (line 1 column 9) | Yes |
| [1, 2,] | Array | Unexpected token ']', "[1, 2,]" is not valid JSON | No |
| {"a": {"b": 1,}} | Nested object | Expected double-quoted property name in JSON at position 14 (line 1 column 15) | Yes |
| {"a": [1, 2,]} | Nested array | Unexpected token ']', "{"a": [1, 2,]}" is not valid JSON | No |
| { "a": 1, } | Object across lines | Expected double-quoted property name in JSON at position 12 (line 3 column 1) | Yes |
| {"a": [1,], "b": {"c": 2,},} | Several at once | Unexpected token ']', "{"a": [1,], "b": {""... is not valid JSON | No |
3 of these are object cases and all 3 report a position. 3 are array cases and none of them do. The pattern tracks the container exactly, not the nesting depth or the document size.
Why the two messages differ
After a comma inside an object, only one thing may legally follow: a double-quoted property name. V8 can say precisely what it expected and where, so it does.
After a comma inside an array, what may follow is a value — an object, an array, a string, a number, or a literal. There is no single token to name. V8 falls back to reporting the token it actually found, the closing ], and prints a fragment of your document instead of coordinates.
On a one-line fixture that fragment is the whole document and the difference looks cosmetic. On anything realistic it is not:
{
"users": [
{ "id": 1, "name": "ada" },
{ "id": 2, "name": "bob" }
],
"meta": { "page": 1, }
}Expected double-quoted property name in JSON at position 106 (line 6 column 24)Line 6, column 24 — the closing brace, one character past the comma. Now the same document with the comma moved into the array:
{
"users": [
{ "id": 1, "name": "ada" },
{ "id": 2, "name": "bob" },
],
"meta": { "page": 1 }
}Unexpected token ']', ..."bob" },
],
"meta"... is not valid JSONNo position, no line, no column. The excerpt keeps the original line breaks, so the error itself arrives split across several lines. In a file of any size that is what you have to work with.
Finding the comma when nothing is located
- 1. If you were given a position, read the character just before itFor an object, the position points at the closing brace or the next property name — so the stray comma is immediately before it, usually at the end of the previous line.
- 2. If you were given no position, the comma is in an arrayThat is itself the most useful thing the message tells you. It narrows the search to array literals, which are usually a small fraction of a document, and rules out every object.
- 3. Read the excerpt V8 prints insteadThe message includes a fragment of the document surrounding the failure. It is awkward to read because it keeps the original line breaks, but it does identify which array — search the file for that fragment.
- 4. Search for the pattern rather than reading the fileA comma followed only by whitespace and then a closing bracket or brace is the whole defect. A regular expression such as ,\s*[\]}] finds every instance in one pass, including the ones you were not told about.
- 5. Fix at the producer where the JSON was generatedSerializers never emit trailing commas. A document containing one was almost certainly assembled by hand or by string concatenation, and the same source will produce more of them.
# Every trailing comma in one pass — a comma, then only
# whitespace, then a closing bracket or brace.
grep -nE ',[[:space:]]*[]}]' data.json
# In an editor, the equivalent search is:
,\s*[\]}]The search is worth running even when you were given a position. A parser stops at the first problem, so a document with one trailing comma often has several.
What Python reports
Python splits the same way, with different wording, and — unlike V8 — it gives a position for both:
| Input | Python 3.9.6 |
|---|---|
| {"a": 1,} | Expecting property name enclosed in double quotes: line 1 column 9 (char 8) |
| [1, 2,] | Expecting value: line 1 column 7 (char 6) |
| {"a": {"b": 1,}} | Expecting property name enclosed in double quotes: line 1 column 15 (char 14) |
| {"a": [1, 2,]} | Expecting value: line 1 column 13 (char 12) |
| { "a": 1, } | Expecting property name enclosed in double quotes: line 3 column 1 (char 12) |
| {"a": [1,], "b": {"c": 2,},} | Expecting value: line 1 column 10 (char 9) |
So if you have both runtimes available, running the document through Python locates an array trailing comma that V8 will not. That is a genuinely useful reason to reach for the other engine, rather than a curiosity.
JSON, JavaScript, and JSON5
The reason this mistake is so common is that the same text is legal in the language most people write it in. JavaScript object and array literals permit a trailing comma, and editors format code that way by default.
| Format | Trailing comma | [1,,2] | Note |
|---|---|---|---|
| JSON (RFC 8259) | Rejected | Rejected | The grammar has no allowance for either. |
| JavaScript literal | Allowed | Allowed | [1,,2] is a hole, and becomes [1,null,2] once serialised. |
| JSON5 2.2.3 | Allowed | Rejected | Permits a comma after the last item, not an omitted one. |
Note the middle column against the third. JavaScript is the more permissive of the two non-standard options: it accepts an omitted element as well as a trailing one, and quietly turns the gap into null.
// JavaScript, not JSON:
const a = [1, , 2];
a.length // 3
JSON.stringify(a) // "[1,null,2]" <- the hole became null
// JSON5 refuses the same text:
JSON5.parse('[1,,2]') // SyntaxError: invalid character ',' at 1:4If you control the consumer and want trailing commas deliberately, JSON5 and JSONC exist for exactly that. Neither is JSON, and a standard parser will still reject their output — that trade-off is a subject of its own.
Checking a document
Pasting the document into the JSON Formatter reports V8's message against the text you pasted. For an object trailing comma that means a position with a line and column you can act on. For an array trailing comma it means the message above, without a location — because V8 supplies none, and the formatter does not invent one.
It does not remove the comma. There is no repair mode: invalid input produces the error and no output, and Format and Validate agree on every case. Once the document is valid it is formatted, which is a quick way to confirm you found all of them — {"a": 1, "b": [1, 2]} parses cleanly. Parsing runs in your browser, so a payload containing real data is not uploaded anywhere.
If your message is different
| Message | Means |
|---|---|
| Expecting property name enclosed in double quotes | Python's wording — a trailing comma is one of three causes |
| Unexpected end of JSON input | The document stopped where a value was due, rather than having a stray comma |
| Unexpected token '<' | An HTML page arrived instead of JSON |
The first is worth following up: Python raises Expecting property name enclosed in double quotes for a trailing comma and for two other mistakes that have nothing to do with commas, so the message alone will not tell you which you have. If instead the document simply stops early, Unexpected end of JSON input covers that.
Versions measured
Error wording and whether a position is reported are implementation details that change between releases. Every string on this page was produced by:
- Node.js / V8 —
24.16.0 / 13.6 - Python (stdlib json) —
3.9.6 - JSON5 —
2.2.3 - DataToolsHQ JSON Formatter —
native JSON.parse (V8)
The rule underneath does not change: JSON permits no comma after the last item, in every parser and every version.