Як виправити помилки розбору JSON: покроковий розбір Unexpected token
Головне: Перетворіть помилки JSON.parse на рядок і символ, а потім виключіть шість причин: висячі коми, одинарні лапки, коментарі, керівні символи, BOM і обрізання.

Коротко: під час помилки розбору прочитайте вказані рядок і стовпець, щоб знайти перший недопустимий символ, а далі визначте, це пропущена лапка, пропущена кома, висяча кома, 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 Notepad, містить три байти EF BB BF. JSON.parse повідомляє Unexpected token, коли натрапляє на BOM, а око його взагалі не бачить. Як визначити: перегляньте заголовок файлу в шістнадцятковому вигляді або копіюйте вміст в онлайн-інструмент і подивіться, чи перший символ показується як . Виправлення: збережіть як «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. П'ятихвилинний робочий процес виправлення
- Вставте в інструмент: спершу скористайтеся онлайн-парсером, щоб знайти першу помилку, і виправляйте лише одну за раз;
- Перевіряйте після кожного виправлення: повторно розбирайте після кожної зміни, щоб виправлення кількох місць одразу не дало новим помилкам замаскувати стару;
- Один раз мініфікуйте: приберіть пробільні символи через Мініфікацію і розберіть знову; це відрізняє «структурні помилки» від «проблем із пробільними символами чи переведеннями рядка»;
- Порівняйте структуру: якщо після зміни раптом з'явилася помилка, скористайтеся JSON diff проти попередньої версії; різниця зазвичай — одна кома;
- Перевірка на рівні полів: якщо синтаксис проходить, а бізнес-рівень відхиляє (відсутнє поле, неправильний тип), це належить до перевірки 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 — це відступ символу від нуля, а не номер рядка, тоді як Java Jackson і Python одразу дають рядок і стовпець. Вставте JSON у онлайн-парсер JSON, і інструмент поставить курсор на місце помилки та підсвітить рядок і стовпець. Якщо помилка на самому початку, перевірте заголовок файлу на BOM і пошукайте невидимі символи.
Чому конфігурація, копійована з коду, так часто містить висячу кому?
Специфікація JSON забороняє висячі коми, а об'єктні літерали JavaScript їх дозволяють, тож конфігурація, копійована з JS-коду, легко тягне її за собою. Виправлення просте — видалити останню кому; якщо дані все одно належать JS-файлу, перехід на конвертацію в JSON5 підходить краще, ніж вганяти їх у JSON.
Чи можна розібрати файл конфігурації з коментарями як звичайний JSON?
Ні — у граматиці RFC 8259 немає місця для коментарів, тож прямий розбір дасть помилку. Або видаліть коментарі, або збережіть як .jsonc / .json5 і використовуйте парсер із підтримкою коментарів. Про компроміси між схемами коментарів дивіться Як писати коментарі в JSON.