JSON Toolkit

Как исправить ошибки разбора JSON: пошаговая проверка Unexpected token

Главное: Превратите ошибку JSON.parse в номер строки и символа, а затем исключите шесть причин: завершающие запятые, одинарные кавычки, комментарии, управляющие символы, BOM и обрыв данных.

Начинающий~12 мин чтенияОпубликовано 2026-10-30Обновлено 2026-11-01
Обложка о диагностике ошибок разбора JSON

Коротко: при ошибке разбора читайте указанные строку и столбец, чтобы найти первый недопустимый символ, и затем решите, дело в пропущенной кавычке, пропущенной запятой, завершающей запятой, BOM или обрыве данных, — не перечитывайте весь документ с начала.

Сообщение об ошибке никогда не говорит «что именно не так»; оно говорит лишь «где парсер больше не смог продолжить». Эти две позиции часто оказываются разными местами.

1. Сначала превратите ошибку в координаты

Один и тот же битый JSON даёт совершенно разные ошибки в разных языках, но все их можно свести к «какая строка, какой символ»:

Среда Типичная ошибка Как её читать
Браузер / Node Unexpected token } in JSON at position 42 position — это смещение символа с нуля, а не номер строки
Node 20+ Unexpected non-whitespace character after JSON at position 42 значит, первая часть корректна, а лишнее содержимое начинается после 42
Java Jackson Unexpected character ('}' (code 125)): was expecting ... at [Source: (String)..."..." ; line: 3, column: 1] сразу даёт строку и столбец — самый удобный вариант
Python json.decoder.JSONDecodeError: Expecting ',' delimiter: line 3 column 1 (char 42) char — это смещение, а важны строка и столбец
Go invalid character '}' looking for beginning of object key string даёт только символ, поэтому позицию приходится находить самому

Когда позиция известна, вставьте JSON в онлайн-парсер JSON: инструмент ставит курсор в место ошибки и подсвечивает номер строки и столбца — этот шаг экономит 90% всматривания в символы.

2. Шесть частых ошибок

1. Завершающая запятая

{
  "name": "json",
  "version": 1,
}

Перед } стоит лишняя запятая. Спецификация JSON не допускает завершающих запятых, а литералы объектов JavaScript допускают, поэтому конфигурация, скопированная из кода, чаще всего несёт её с собой. Исправление: удалите последнюю запятую; если эти данные изначально живут в JS-файле, перейдите на конвертацию в JSON5, а не загоняйте их в JSON силой.

2. Одинарные кавычки и ключи без кавычек

{ 'name': 'json' }
{ name: "json" }

Строки JSON могут использовать только двойные кавычки, и ключи тоже должны быть строками в двойных кавычках. Эти две формы — послабление синтаксиса JSON5 / JavaScript, а не JSON. Двойную кавычку внутри строки нужно записывать как \", а обратную косую черту — как \\.

3. Комментарии

{
  // Timeout in milliseconds
  "timeout": 3000
}

В грамматике RFC 8259 для комментариев места нет. Либо удалите комментарии, либо сохраните файл как .jsonc / .json5 и используйте парсер, поддерживающий комментарии. О компромиссах разных «схем комментирования» читайте в статье Как писать комментарии в JSON.

4. Необработанные переводы строк и управляющие символы внутри строк

{"sql": "SELECT *
FROM t"}

Строки JSON не могут содержать необработанные переводы строки, табуляцию и управляющие символы U+0000–U+001F; их нужно записывать как \n, \t, \u0009. Когда вставляете многострочный текст в JSON, сначала экранируйте его в редакторе или обработайте единообразно с помощью минификации и экранирования JSON.

5. Заголовок BOM

UTF-8, сохранённый «Блокнотом» Windows, несёт три байта EF BB BF. JSON.parse при встрече с BOM сообщает Unexpected token, а глазами его вообще не видно. Как проверить: посмотрите начало файла в шестнадцатеричном виде или вставьте содержимое в онлайн-инструмент и проверьте, отображается ли первый символ как . Исправление: сохраните файл в варианте «UTF-8 без BOM».

6. Обрезанное содержимое

Лог, в который попали только первые 4096 символов, ответ API, обрезанный шлюзом, прерванная загрузка — отличительная черта этого класса в том, что «ошибка находится в конце», а количество скобок не сходится. Сначала посчитайте скобки: если закрывающие } и ] не совпадают с открывающими, это обрыв, а не синтаксическая ошибка. В таком случае ничего не исправляйте — идите за полными данными.

3. Две ложные тревоги, связанные с китайским текстом и экранированием

Китайский превращается в \u4e2d\u6587: это допустимое экранирование JSON, а не «кракозябры». После разбора значение восстанавливается в китайский текст; форма \u видна, только если смотреть на сырую строку напрямую. Когда нужно показать это людям, просто выведите результат через инструмент форматирования; об стратегии экранирования стоит думать, только если китайский текст должен выжить в URL или логе.

Китайский превращается в кракозябры вроде 涓枃: это проблема кодировки, а не JSON. Так бывает, когда байты UTF-8 декодируются как GBK и получается характерный узор «три символа вместо одного иероглифа». Проверьте заголовок ответа Content-Type: application/json; charset=utf-8 и уточните, задаётся ли encoding='utf-8' явно при чтении файла.

4. Пятиминутный порядок починки

  1. Вставьте в инструмент: сначала с помощью онлайн-парсера найдите первую ошибку и исправляйте только одну за раз;
  2. Проверяйте после каждого исправления: заново разбирайте после каждого изменения, чтобы исправление нескольких мест сразу не позволило новым ошибкам замаскировать старую;
  3. Минифицируйте один раз: уберите пробелы через минификацию и разберите снова; это отличает «структурные ошибки» от «проблем с пробелами и переводами строк»;
  4. Сравните структуру: если после изменения внезапно появилась ошибка, сравните с предыдущей версией через JSON diff; разница обычно и есть та самая одна запятая;
  5. Валидация на уровне полей: если синтаксис проходит, а бизнес-логика данные не принимает (нет поля, неверный тип), это уже валидация JSON Schema, а не синтаксическая проблема.

5. Почему один из двух «одинаковых» фрагментов JSON разбирается, а другой нет

Самая частая причина — невидимые символы: полноширинная запятая ,, полноширинные кавычки “”, неразрывный пробел U+00A0, пробел нулевой ширины U+200B. На экране они почти неотличимы от полуширинных аналогов, но ни один из них не входит в грамматику JSON.

Есть только один способ проверить: скопируйте фрагмент вокруг подозрительного символа и просмотрите кодовые точки посимвольно. Следующий код в консоли браузера выведет все символы, которые не являются ASCII и не попадают в китайские диапазоны:

[...text].filter((ch) => {
  const code = ch.codePointAt(0);
  return code > 127 && !(code >= 0x4e00 && code <= 0x9fff);
});

Если в выводе появились 0x201c (левая двойная кавычка), 0xff0c (полноширинная запятая) или 0x00a0, виновник найден.

6. Профилактика дешевле ремонта

  • Прогоняйте проверку разбора конфигурационных файлов перед коммитом; в CI достаточно одной строки: node -e "JSON.parse(require('fs').readFileSync('config.json','utf8'))";
  • Генерируйте ответы API библиотекой сериализации; никогда не склеивайте строки вручную — только собранные руками строки дают завершающие запятые и пропущенные кавычки;
  • При логировании JSON сначала вызывайте JSON.stringify, а не подставляйте его в шаблон, чтобы недописанный объект не приняли за полное сообщение.

Вопросы и ответы

Как быстро найти место синтаксической ошибки JSON?

Возьмите position или строку и столбец, которые сообщает парсер; position — это смещение символа с нуля, а не номер строки, тогда как Java Jackson и Python сразу сообщают строку и столбец. Вставьте JSON в онлайн-парсер JSON, и инструмент поставит курсор в место ошибки и подсветит строку со столбцом. Если ошибка находится в начале, проверьте начало файла на BOM и поищите невидимые символы.

Почему конфигурация, скопированная из кода, так часто несёт завершающую запятую?

Спецификация JSON запрещает завершающие запятые, а литералы объектов JavaScript их допускают, поэтому конфигурация, вытащенная из JS-кода, легко приносит её с собой. Исправление простое — удалить последнюю запятую; если данные всё равно относятся к JS-файлу, конвертация в JSON5 подходит лучше, чем насильно загонять их в JSON.

Можно ли разобрать конфигурационный файл с комментариями как обычный JSON?

Нет — в грамматике RFC 8259 для комментариев места нет, поэтому прямой разбор выдаст ошибку. Либо удалите комментарии, либо сохраните файл как .jsonc / .json5 и используйте парсер с поддержкой комментариев. О компромиссах схем комментирования читайте в статье Как писать комментарии в JSON.