Довідник повідомлень про помилки JSON: від тексту помилки просто до виправлення
Головне: Знаходьте причину за точним повідомленням JSON.parse: 12 частих помилок у Chrome, Firefox і Safari, зокрема HTML-сторінки помилок, обрізання й подвійний розбір.

Коротко: коли з'являється помилка JSON.parse, спершу схопіть позицію й токен; позиція 0 означає перевірку на HTML-відповідь, BOM чи неправильний тип, а повідомлення «Expected» означає, що треба дивитися на попередній символ — не перечитуйте рядок за рядком від вказаної позиції.
Текст помилки — це не шум, а відповідь. Парсер каже, на який символ натрапив, чого очікував і що насправді отримав. Пошук за повідомленням про помилку краще за ручне переписування всього документа.
Кожна помилка JSON.parse() складається з трьох частин: позиція (відступ символу або рядок/стовпець), очікування (Expected...) і реальність (Unexpected token X або xxx is not valid JSON). Рушії формулюють їх по-різному — Chrome і Node (V8) кажуть Expected ',' or '}' after property value in JSON at position 25, Firefox каже JSON.parse: expected ',' or '}' after property value in object at line 3 column 1, Safari каже JSON Parse error: Expected ',' or '}' — але всі три вказують на той самий синтаксичний злам. Коли шукаєте помилку, ігноруйте формулювання й схопіть три факти: який символ, чого очікували, що надійшло.
1. Таблиця 12 помилок
Ліва колонка — найбільш упізнаваний фрагмент із вашої консолі (формулювання V8). Варіанти Firefox/Safari — у дужках.
| Текст помилки (V8) | Справжня причина | Виправлення |
|---|---|---|
Unexpected token < in JSON at position 0 |
API повернув HTML (сторінку 404, шаблон 500, перенаправлення на логін, запасний варіант проксі), а не JSON | Спершу перевірте response.status і Content-Type; не виправляйте JSON |
Unexpected end of JSON input |
Вхід порожній або обрізаний: порожнє тіло, 204, перерване завантаження, копія без останнього рядка | Обробіть порожній випадок, порівняйте Content-Length, щоб знайти обріз |
Unexpected token o / "[object Object]" is not valid JSON |
Уже розібраний об'єкт знову передали в JSON.parse() і приведено до рядка |
Перевірте typeof; якщо це об'єкт, використовуйте його безпосередньо |
"undefined" is not valid JSON |
Змінній ніколи не присвоювали значення (JSON.parse(undefined)) |
Ініціалізуйте резервні значення; перевіряйте перед розбором |
Expected double-quoted property name in JSON |
Висяча кома ({"a": 1,}); парсер очікує ще один ключ і знаходить } |
Видаліть кому після останнього елемента |
Expected property name or '}' in JSON |
Ключ без лапок або в одинарних лапках ({name: "Ada"}, {'name': 'Ada'}) |
Беріть кожен ключ у подвійні лапки |
Expected ',' or '}' after property value in JSON |
Пропущена кома ({"a": 1 "b": 2}) або коментар після значення |
Додайте кому; приберіть коментар |
Unexpected token '/' |
Коментар // або /* */ усередині JSON |
Видаліть його або розбирайте конфігурацію як JSONC |
Bad control character in string literal |
Сирий перевід рядка, табуляція чи інший керівний символ U+0000–U+001F усередині рядка | Пишіть \n; генеруйте через JSON.stringify |
Unterminated string in JSON |
Рядок відкрито лапкою " і не закрито, або внутрішню лапку не екрановано |
Екрануйте внутрішні лапки як \" |
Unexpected non-whitespace character after JSON |
Два документи в одному тексті: {}{}, NDJSON, обгортка JSONP |
Розділіть за рядками й розбирайте кожен, або використовуйте парсер NDJSON |
JSON.parse is not a function |
Ваша власна змінна затіняє глобальний JSON |
Перейменуйте змінну; ніколи не називайте її JSON |
Перші дві варті ближчого погляду, бо жодна не означає «ваш JSON неправильний» — вони означають «те, що ви отримали, не те, чим ви його вважаєте».
2. Три часті джерела помилки з позицією 0
Позиція 0 означає, що найперший символ недопустимий. Якщо ніщо не виглядає підозрілим, символ, найімовірніше, невидимий. Три звичні підозрювані:
Перший: <, тобто HTML. Це найчастіша помилка розбору у виробництві. Неправильний URL, сесія, що закінчилася і була перенаправлена шлюзом, або шаблон помилки сервера — тіло починається з <!DOCTYPE html>, і парсер здається на першому ж символі. Правильний крок — відкрити панель Network і прочитати сиру відповідь, а потім виправити виклик API, а не JSON.
Другий: BOM або символи нульової ширини. Файли, збережені Windows Notepad, часто починаються з BOM UTF-8 (\uFEFF), а текст, копійований зі сторінок або чатів, може містити пробіли нульової ширини (\u200B–\u200D). Для вас невидимі, для парсера очевидні:
// Прибрати BOM і символи нульової ширини перед розбором
const cleaned = raw.replace(/^\uFEFF/, '').replace(/[\u200B-\u200D]/g, '');
const data = JSON.parse(cleaned);
Третій: неправильний тип. JSON.parse(undefined) повідомляє "undefined" is not valid JSON; JSON.parse(someObject) повідомляє Unexpected token o (об'єкт приведено до "[object Object]", а o недопустимий на позиції 1). Обидва означають «дані вже розібрані» або «даних ніколи не було». Перевіряйте тип, а не синтаксис:
let data = text;
if (typeof data === 'string') {
data = JSON.parse(data); // Розбирайте, лише коли це справді рядок
}
3. Позиція вказує нижче за течією, а причина — вище
Дві помилки вводять в оману щодо місця, і це два найбільш неправильно прочитані записи таблиці:
- Пропущена кома:
{"a": 1 "b": 2}повідомляєExpected ',' or '}' after property valueу рядку з"b". Повідомлення правильне, але виправлення належить у кінець попереднього рядка. - Пропущена закривна дужка: глибока вкладеність без одного
}або]змушує парсер проковтнути все до кінця вводу й повідомитиUnexpected end of JSON input. Позиція — кінець файлу; справжній розрив може бути набагато раніше. Шукайте назад найостанніший незакритий{або[— підрахунок пар краще за вдивляння.
Загальна техніка — бісекція: відріжте текст до вказаної позиції й розберіть його окремо. Якщо розбирається, проблема близько до вказаної позиції; якщо ні — діліть далі назад. Межа першого фрагмента, що не розбирається, і є справжнім місцем помилки. Для великих файлів спершу відформатуйте документ — з вирівняними відступами пропущений рівень видно одразу (онлайн-форматувальник JSON чудово для цього підходить).
4. Чотири «хибно здорові» стани, що розбираються нормально, але поводяться неправильно
Гірше за помилку — коли помилки немає, а дані неправильні. У всіх чотирьох випадках JSON валідний, а парсер задоволений — проблема у формі даних:
- Подвійне кодування: весь документ було двічі оброблено
JSON.stringify, тож розбір дає рядок, а не об'єкт. Якщоtypeof result === 'string', розберіть ще раз — але знайдіть і виправте подвійну серіалізацію в джерелі. - Повторювані ключі мовчки перезаписують:
{"name": "Tom", "name": "Jerry"}— валідний JSON, більшість парсерів не скаржаться, і перемагає друге значення. Це кусає під час злиття даних із кількох джерел; виявіть це строгим валідатором JSON, перш ніж воно вкусить вас. - NDJSON сприймають як один документ: потокові API видають по одному об'єкту на рядок; розбір усього тексту завершується з
Unexpected non-whitespace character after JSON. Розділіть за\nі розбирайте по рядку. - Тихе втрачання точності чисел: цілі числа, більші за
2^53 - 1(ID сніжинки), повертаються із зануленими останніми цифрами, без жодної помилки. Передавайте ID як рядки.
Спільна нитка: парсер вважає, що все гаразд. Тож коли дані API виглядають неправильно, спершу виведіть перші 80 символів сирого тексту та його typeof — підтвердьте форму, перш ніж обговорювати вміст.
5. Зробіть помилки неможливими під час запису
Таблиця — інструмент після факту; профілактика — інструмент до факту. Чотири звички перехоплюють більшість помилок до того, як вони стануться:
// 1. Дві перевірки перед розбором будь-якої відповіді
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: the API returned no data`);
}
const contentType = response.headers.get('content-type') ?? '';
if (!contentType.includes('application/json')) {
throw new Error(`Expected JSON, got ${contentType}`);
}
const data = await response.json(); // 2. json() уже розбирає — не розбирайте знову
- Серіалізуйте, щоб генерувати, ніколи не склеюйте:
JSON.stringify()правильно обробляє лапки, переведення рядків і керівні символи; рядки, складені вручну, — головне джерелоBad control characterтаUnterminated string. - Завжди перехоплюйте: викинута помилка
JSON.parse— це синхронний збій, якщо її ніщо не перехоплює. Для недовіреного вводу — localStorage, зовнішні файли — блоку catch потрібне значення за замовчуванням або явне повідомлення про помилку. - Доручайте структуру схемі: валідний синтаксис не означає валідну структуру. Відсутні поля й неправильні типи належать перевірці JSON Schema на межі; дивіться що вирішує JSON Schema.
6. Швидкий шлях рішення
Стисніть усю статтю в один порядок рішень. Коли бачите помилку, спершу схопіть позицію й токен:
- Позиція 0 → перевірте три джерела:
<(HTML), BOM, неправильний тип; end of input→ перевірте порожнє чи обрізане тіло, потім пошукайте назад незакриті дужки;Expected ...→ подивіться на попередній символ; зазвичай це пропущена кома або лапка;after JSON data→ кілька документів склеєно; розділіть за рядком;- Розбирається нормально, але дані виглядають неправильно → виконайте чотири перевірки «хибно здорових» станів.
Разом із покроковим тріажем у як виправити помилки розбору JSON 90% проблем розбору вирішуються за п'ять хвилин. Тримайте сам текст помилки в закладках — це журнал налагодження, який парсер написав для вас; його формулювання змінюється раз на три роки, і один пошук окупає рік.
Що означає «Unexpected token in JSON»?
Парсер натрапив на символ, недопустимий у цьому місці граматики JSON. Токен — це відхилений символ: < зазвичай означає, що API повернув HTML, ' означає одинарні лапки, / означає коментар, а звичайна літера зазвичай означає ключ без лапок або літерал, що існує лише в JavaScript, як-от undefined чи NaN. Прочитайте спершу токен, потім позицію, і причина звужується до однієї.
Як виправити «Unexpected end of JSON input»?
Два джерела: порожній вхід (порожнє тіло відповіді або порожній рядок у localStorage) чи обрізаний вхід (перерване завантаження, копія без останнього рядка, обмеження розміру). Обробіть порожній випадок через if (!text) return; потім перевірте повноту й закрийте найостанніший незакритий {, [ або ". Зауважте, що помилка може також походити від глибоко пропущеної дужки — позиція просто випадково збігається з кінцем файлу.
Чому Chrome, Firefox і Safari повідомляють про помилки по-різному?
Три браузери мають різні рушії JS (V8, SpiderMonkey, JavaScriptCore), і кожен формулює свої помилки по-своєму; MDN документує всі офіційні варіанти. Але всі три помилки містять ті самі три елементи — позицію, очікування, реальність — з однозначною відповідністю. Перекладіть на формулювання V8 і користуйтеся цією таблицею як є.
Позиція помилки вказує туди, де все виглядає добре — що тепер?
Справжня помилка раніше. Типові випадки: пропущена кома (повідомлена в наступному рядку) і пропущена закривна дужка (повідомлена в кінці файлу). Ідіть назад від вказаної позиції токен за токеном або діліть навпіл: розберіть першу половину окремо, і межа першого фрагмента, що не розбирається, буде справжнім місцем помилки.