Почему висячая запятая ломает JSON
Главное: Висячие запятые легальны в литералах объектов JavaScript и фатальны в JSON. Вот точная ошибка, грамматика RFC 8259, которая её вызывает, и три исправления, которые действительно работают.

Главное: JSON запрещает висячие запятые везде — когда парсер падает, удалите последнюю запятую форматтером; используйте JSON5 или JSONC только для локального снисходительного парсинга и всегда выдавайте стандартный JSON другим системам.
Потому что так говорит грамматика.
{
"name": "demo",
"size": 12,
}
JSON.parse выбрасывает Unexpected token } in JSON at position 34. Node формулирует иначе, но каждый движок указывает на одно место: запятую перед }.
На что на самом деле жалуется парсер
Продукция объекта в RFC 8259:
object = begin-object [ member *( value-separator member ) ] end-object
Квадратные скобки означают необязательное, звёздочка — ноль или более. Простыми словами: запятые разделяют члены, а за последним членом сразу идёт }.
Итак, после запятой парсер готов к имени ещё одного члена. Он читает } и падает. Массивы ведут себя идентично — [1, 2, 3,] падает на ].
Откуда берётся привычка
Литералы объектов JavaScript допускают висячие запятые с ES5, как и списки Python и составные литералы Go. Редакторы добавляют их автоматически. Затем кто-то копирует литерал объекта из файла .js в файл .json, и файл перестаёт парситься.
Другой частый источник — сборка JSON вручную: цикл, который выполняется при i <= length, оставляет запятую после последнего элемента.
Три исправления
Удалите запятую. Нормально для ручных правок. Вставьте в форматтер JSON, и ошибка сообщается со строкой и столбцом, так что вы видите точно, какую удалить.
Разберите как JSON5. Надмножества принимают висячие запятые, что нормально для локальной конфигурации. Это не нормально для всего, что вы отправляете другой системе — получатель всё равно отвергнет это.
Прекратите конкатенировать строки. Используйте JSON.stringify, json.dumps, Jackson. Сериализатор правильно обрабатывает разделители и одновременно решает экранирование.
Быстрый контрольный список
| Где | Типичная причина |
|---|---|
| Конкатенация в цикле | i <= length оставляет лишнюю запятую |
| Копирование-вставка | Литерал объекта, поднятый из файла JS |
| Шаблоны | Захардкоженная запятая плюс цикл, добавляющий ещё одну |
| Ручная правка | Последнее поле удалено, его запятая осталась |
Вопросы и ответы
Почему висячие запятые легальны в JavaScript, но не в JSON?
Литералы объектов JavaScript допускают их с ES5, как и списки Python и составные литералы Go, поэтому привычка следует за людьми в JSON. RFC 8259 разрешает запятые только между членами: за последним членом сразу идёт } или ]. Копирование литерала объекта из файла .js в файл .json — обычный источник.
Стоит ли разбирать как JSON5, чтобы принимать висячие запятые?
Только для локальной конфигурации. Надмножества принимают висячие запятые, но всё, что вы отправляете другой системе, парсится как строгий JSON и всё равно упадёт. Генерируйте стандартный JSON на границе вывода вместо того, чтобы рассчитывать на снисходительность получателя.
Куда смотреть первым после ошибки висячей запятой?
Начните с позиции в сообщении об ошибке: она обычно указывает на запятую перед } или ]. Затем проверьте три обычных источника: цикл, написанный с i <= length, литерал объекта, вставленный из файла JS, и шаблон, который захардкодил запятую рядом с циклом. Вставка в форматтер сообщает точную строку и столбец.