Unexpected token в JSON: причины и решение

Почему JSON.parse встретил не тот символ и что с этим делать

Unexpected token значит, что JSON.parse встретил символ, с которого JSON не может начинаться или продолжаться. Если этот символ — < в позиции 0, вместо JSON пришла HTML-страница: ошибка сервера, страница входа или index.html. Проверьте статус и тело ответа во вкладке «Сеть» — сам JSON здесь ни при чём.

Как выглядит ошибка в разных браузерах

Одна и та же поломка в разных движках описана по-разному. Для ответа, который начинается с <!DOCTYPE html>, сообщения такие:

  • Chrome, Edge и Node.js 20 и новее: SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON;
  • Chrome до середины 2022 года и Node.js 18 и старше: SyntaxError: Unexpected token < in JSON at position 0;
  • Firefox: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data;
  • Safari: SyntaxError: JSON Parse error: Unrecognized token '<'.

Во всех четырёх случаях сказано одно: первый же символ — не начало JSON. В новых Chrome и Node.js в кавычках после «Unexpected token» — сам символ, а дальше начало текста, который пытались разобрать. Это первая подсказка: если там <!DOCTYPE или <html>, разбирали HTML.

Unexpected token < в позиции 0: сервер вернул HTML

Код ждал JSON и вызвал response.json() или JSON.parse, а пришла веб-страница. Типичные причины:

  • страница ошибки 404 или 500: неверный адрес API, опечатка в пути, упал бэкенд, и веб-сервер или прокси ответил своей HTML-заглушкой;
  • редирект на страницу входа: истекла сессия или не передан токен, и вместо данных пришла форма логина;
  • фоллбэк одностраничного приложения: сервер на любой неизвестный адрес отдаёт index.html, в том числе на /api/…, если запрос не дошёл до бэкенда — например, не настроен прокси в режиме разработки;
  • заглушка балансировщика, CDN или защиты от ботов: страница «502 Bad Gateway» или проверка браузера.

Поэтому искать ошибку в JSON бесполезно: его в ответе нет. Нужно понять, почему сервер ответил страницей.

Как убедиться, что пришёл HTML

  • Откройте инструменты разработчика (F12), вкладку «Сеть» (Network), повторите запрос и выберите его. Посмотрите статус: 401, 403, 404, 500, 502 или 302 с переходом на страницу входа сразу объясняют дело. Во вкладке ответа будет HTML.
  • Посмотрите заголовок ответа Content-Type: у JSON это application/json, у страницы — text/html.
  • В коде прочитайте тело как текст и выведите начало: const text = await response.text(); console.log(response.status, text.slice(0, 200));

Как правильно обработать ответ в fetch

fetch не считает статус 404 или 500 ошибкой: промис выполняется успешно, и код спокойно вызывает response.json() на HTML-странице. Проверяйте response.ok и тип содержимого до разбора:

Проверка статуса и Content-Type перед разбором
const response = await fetch('/api/orders');
const type = response.headers.get('Content-Type') ?? '';

if (!response.ok || !type.includes('application/json')) {
  const text = await response.text();
  throw new Error(`Ждали JSON, получили ${response.status} ${type}: ${text.slice(0, 200)}`);
}

const data = await response.json();

Так в логе будет видно, что сервер вернул на самом деле, а не загадочный «Unexpected token». Для запросов без тела, например со статусом 204, response.json() вызывать не нужно вовсе — получите «Unexpected end of JSON input».

Unexpected token u: разбирают undefined

Если в JSON.parse передать undefined, он превращается в строку "undefined" и падает на первой букве. Старые Chrome и Node.js пишут Unexpected token u in JSON at position 0, новые — "undefined" is not valid JSON. Обычно это опечатка в имени поля (data.reponse вместо data.response), переменная, которую забыли заполнить, или функция, которая ничего не вернула. Проверьте значение до разбора. Заметьте: JSON.parse(null) ошибки не даёт и возвращает null — поэтому отсутствующий ключ в localStorage эту ошибку не вызывает.

Unexpected token o: разбирают уже готовый объект

Объект, переданный в JSON.parse, приводится к строке "[object Object]". Первый символ [ подходит для начала массива, а следующий o — уже нет. Отсюда старое сообщение Unexpected token o in JSON at position 1 и новое "[object Object]" is not valid JSON. Значит, данные уже разобраны: response.json(), axios или jQuery сделали это за вас. Второй JSON.parse не нужен.

Другие неожиданные символы

  • Невидимый символ в позиции 0 — скорее всего, BOM в начале файла. В новых Chrome и Node.js сообщение выглядит так, будто после «Unexpected token» в кавычках пусто: там стоит невидимый символ U+FEFF. Python в этом случае прямо пишет «Unexpected UTF-8 BOM». Сохраните файл в UTF-8 без BOM.
  • ' — строка или ключ в одинарных кавычках. В новых Chrome и Node.js для ключа это Expected property name or '}' in JSON, для значения — Unexpected token '''.
  • } или ] сразу после запятой — висячая запятая. Перед } новые версии пишут Expected double-quoted property name in JSON, перед ] — Unexpected token ']'.
  • T, N — True, None или NaN из Python. Сообщение: Unexpected token 'T', ... is not valid JSON.
  • “ или « — типографские кавычки, которые подставили Word или мессенджер.

Подробнее о каждой из этих ошибок — в статье «Ошибки в JSON и как их исправить».

Апдейт Telegram после ручной правки: одинарные кавычки и висячая запятая
{
  "update_id": 815104223,
  "message": {
    "chat": { "id": 52017733, 'type': 'private' },
    "text": "/start",
  }
}

Как перевести позицию в строку и колонку

Старые версии Chrome и Node.js сообщают только «position 214» — номер символа от начала текста. В большом файле с отступами найти 214-й символ вручную неудобно. Новые версии Chrome и Node.js дописывают строку и колонку, а Firefox указывает их всегда.

Проще вставить текст в проверку JSON на parsetools: она покажет все ошибки сразу, с номером строки и колонки, подчеркнёт место и объяснит причину по-русски. Если ошибки исправимы автоматически — кавычки, запятые, литералы Python, — починка исправит их и покажет список правок. Текст не уходит на сервер: всё работает в браузере.

Частые вопросы

Unexpected token < in JSON at position 0 что делать

Вместо JSON пришла HTML-страница. Откройте вкладку «Сеть» в инструментах разработчика, найдите запрос и посмотрите статус и тело ответа: чаще всего это 404, 500 или переход на страницу входа. Исправлять нужно адрес запроса или ошибку на сервере.

Что значит is not valid JSON

Так новые Chrome, Edge и Node.js сообщают, что текст не является JSON. Перед этими словами — неожиданный символ и начало разобранного текста: по нему видно, что пришло на самом деле.

Почему fetch не выдаёт ошибку при 404

fetch отклоняет промис только при сетевой ошибке (в том числе при блокировке CORS) или отмене запроса. Ответ с любым статусом считается успешным, поэтому проверяйте response.ok перед вызовом response.json().

Что значит Unexpected token u in JSON at position 0

В JSON.parse передали undefined. Проверьте, откуда берётся значение: поле с опечаткой, пустая переменная, отсутствующий ответ.

JSON.parse unexpected character at line 1 column 1 в Firefox

Первый же символ — не начало JSON. Обычно это HTML-страница вместо данных или BOM в начале файла. Проверьте ответ во вкладке «Сеть».

Инструменты по теме

Ещё в справке