Повідомлення «unexpected token» рідко здається корисним. Видимою причиною може бути пропущена лапка або кома, але в production JSON часто ламається за межами самого документа. Сервер повертає HTML-сторінку помилки, proxy обрізає відповідь, перед першою дужкою з’являється невидимий символ, а лог додає до правильного payload службовий текст. Ефективна діагностика починається не з пошуку коми, а з визначення межі, на якій дані перестали відповідати очікуванню.

Спочатку перевірте, чи відповідь узагалі є JSON

Клієнтський код часто викликає JSON-парсер для кожної відповіді API. Після завершення сесії фреймворк може перенаправити користувача на HTML-сторінку входу. Після аварії сервер може повернути HTML зі stack trace. Парсер тоді скаржиться на символ <, бо бачить початок тегу.

Перед аналізом синтаксису перевірте HTTP-статус, Content-Type, фінальний URL після redirect і сире тіло відповіді. Помилка парсингу може бути лише першим видимим симптомом проблеми авторизації, маршрутизації або сервера.

Зберігайте точний вхід, а не відтворену копію

Копіювання payload із debugger може його змінити: escape-послідовності інтерпретуються, довгі значення обрізаються, невидимі символи зникають. За можливості збережіть сирі байти відповіді або файлу. Порівняйте фактичну довжину з очікуваною й перегляньте початок та кінець.

Номер рядка й позиції корисний лише для того самого вводу, який отримав парсер. Форматування пошкодженого документа може змінити позиції або взагалі не запуститися. Спочатку використовуйте validator, який показує першу синтаксичну помилку без переписування джерела.

JSON суворіший за JavaScript-об’єкт

Назви властивостей і рядки в JSON мають використовувати подвійні лапки. Одинарні лапки, ключі без лапок, trailing comma, коментарі, NaN та Infinity не належать до стандартного JSON. Часто розробник копіює JavaScript literal і очікує, що він пройде JSON-парсер.

Escape усередині рядків є ще одним джерелом помилок. Реальний перенос рядка не можна вставити прямо в JSON-рядок — він має бути записаний як \n. Backslash у Windows-шляхах або регулярних виразах також потребує escape. Коли JSON вкладений в інший рядок, кількість рівнів швидко стає крихкою.

Шукайте обрізання та склеювання документів

JSON може починатися правильно й закінчуватися посеред об’єкта. Timeout, ліміт відповіді, неповний запис файлу або обмеження логування обрізають дані. Перевірте завершальні дужки, але не обмежуйтеся ручним додаванням символу: важливо знайти, чому байти зникли.

Протилежна проблема виникає, коли два правильні JSON-документи записали підряд без роздільника. Парсер завершує перше значення й знаходить неочікуваний текст. Для потоків потрібен визначений framing: newline-delimited JSON, префікс довжини або зовнішній масив.

Кодування символів може зламати правильний синтаксис

JSON у вебі зазвичай використовує UTF-8. Файл у legacy-кодуванні може містити послідовності байтів, які UTF-8-парсер відхилить. Невидимий byte-order mark, control character або незвичайний пробіл також створює помилку, хоча в редакторі текст виглядає нормально.

У такій ситуації потрібен перегляд байтів або hexadecimal representation. Не слід «виправляти» проблему мовчазним видаленням невідомих символів: це може зіпсувати імена, ідентифікатори й зміст, залишивши документ формально валідним.

Відокремлюйте синтаксис від схеми

Синтаксично правильний JSON може бути непридатним для застосунку. API очікує об’єкт, а отримує масив; чекає число, а приходить рядок; потребує обов’язкове поле, якого немає. Це помилки контракту, а не JSON-парсера.

Спочатку парсіть документ, потім перевіряйте отримане значення за схемою. Повідомляйте шлях до проблемного поля та очікуваний тип. Загальна відповідь «invalid JSON» для кожної validation error змушує клієнта шукати синтаксичну проблему, якої не існує.

Запобігайте помилкам у джерелі

Застосунки повинні серіалізувати значення перевіреною бібліотекою, а не будувати JSON конкатенацією рядків. Серіалізатор правильно обробляє лапки, Unicode, масиви, булеві значення та null. Ручне складання ламається, щойно користувацький текст містить лапку або backslash.

На системних межах логування має зберігати достатньо метаданих для діагностики, але не розкривати секретні payload. Contract tests перевіряють статуси, content type і типові відповіді, а моніторинг показує різке зростання parse error ще до звернень користувачів.

Перевіряйте кожен етап перетворення

У складному застосунку JSON проходить через serializer, HTTP-клієнт, proxy, gateway і декілька middleware. Кожен етап може стиснути, обрізати, перекодувати або замінити відповідь. Порівняння сирого значення на вході й виході кожного шару швидше знаходить проблему, ніж багаторазове читання фінального повідомлення парсера.

Особливо корисно відтворити запит поза основним клієнтом: через curl або мінімальний тест. Якщо там відповідь правильна, проблема ймовірно знаходиться в клієнтській обробці. Якщо неправильна — пошук переміщується ближче до сервера.

Не виправляйте неправильний JSON регулярними виразами

Спроба додати лапки, прибрати коми або замінити символи regex-ом може зробити один приклад валідним і пошкодити інший. JSON має вкладену структуру й escape-правила, які не можна надійно відновити простими замінами.

Якщо джерело систематично надсилає не JSON, краще виправити producer або застосувати спеціальний parser для фактичного формату. Мовчазний «ремонт» на стороні отримувача приховує порушення контракту й ускладнює майбутню підтримку.

Сприймайте повідомлення парсера як доказ

Найшвидший шлях до виправлення — не вгадувати, де пропущена кома. Потрібно з’ясувати, хто створив байти, як вони передавалися, які перетворення відбулися й чи збігається очікування отримувача з контрактом. Після цього позиція з повідомлення парсера звузить пошук.

Після виправлення додайте тест із точним проблемним прикладом. Це перетворює одноразову діагностику на захист від повторного виникнення тієї самої помилки.

Зафіксуйте також першопричину, а не лише змінений символ.

Це важливо.

Неправильний JSON часто є проблемою межі, що виглядає як синтаксична помилка. Аналіз сирого вводу, HTTP, кодування та схеми перетворює нечіткий «unexpected token» на конкретну причину.