Ломает ли BOM парсинг JSON
Главное: UTF-8 BOM — это три невидимых байта, поэтому JSON.parse падает на первом символе и сообщает строку 1, столбец 1, из-за чего файл кажется пустым или усечённым.

Главное: проверьте первые три байта на EF BB BF и пересохраните как UTF-8 без BOM; на сервере удаляйте ведущий U+FEFF перед парсингом любого загруженного или стороннего файла, вместо того чтобы отлаживать сбой потом.
Да — и это порождает самую запутанную из всех ошибок парсинга, потому что файл выглядит совершенно нормально.
Что вы видите
SyntaxError: Unexpected token in JSON at position 0
Unexpected character '\uFEFF'
Этот символ в сообщении невидим. Позиция 0 означает самый первый байт.
cat не показывает ничего необычного. hexdump -C file.json | head -1 показывает:
00000000 ef bb bf 7b 0a 20 20 22 61 22 3a 20 31 0a 7d 0a |...{ "a": 1.}.|
7b — это {. Три байта перед ним — BOM.
Откуда берутся BOM
Метка порядка байтов существовала для UTF-16, где порядок байтов действительно различался. У UTF-8 единый порядок байтов, поэтому BOM — чистая переплата — но Блокнот в Windows, некоторые экспорты Excel и ряд старых IDE всё ещё пишут его по умолчанию.
RFC 8259 однозначен: JSON, обмениваемый между системами, должен быть UTF-8, и реализации не должны добавлять BOM. Парсеры могут игнорировать ведущий BOM, но не обязаны. Браузеры и Node решают не делать этого.
Три способа избавиться от него
Сохраните без BOM. В VS Code нажмите на кодировку в строке состояния и выберите «Save with Encoding → UTF-8», а не «UTF-8 with BOM».
Удалите его из оболочки.
sed -i '1s/^\xEF\xBB\xBF//' data.json
Удалите его при чтении. Это надёжное исправление для всего, что принимает загруженные или сторонние файлы:
const text = require('node:fs').readFileSync('data.json', 'utf8').replace(/^\uFEFF/, '');
JSON.parse(text);
В Python open(path, encoding='utf-8-sig') обрабатывает это автоматически.
Две похожие проблемы
- Пробел нулевой ширины (U+200B) — появляется при копировании JSON со веб-страницы; тот же симптом, другая кодовая точка.
- Полноширинные кавычки — китайский IME превращает
"key"в“key”, что выглядит почти идентично, но падает какUnexpected token “.
Все три — баги невидимых символов. Диагностика всегда одна: выгрузите первые байты в hex, а не вглядывайтесь в текст.
Вопросы и ответы
Как понять, начинается ли файл с BOM?
cat ничего не показывает, поэтому выполните hexdump -C file.json | head -1. Если вывод начинается с ef bb bf, в файле есть BOM; в чистом UTF-8-файле первым должен идти 7b (это {).
Почему ошибка всегда указывает на строку 1, столбец 1?
BOM стоит перед всем остальным, поэтому первый символ, который читает парсер, — U+FEFF. Сбой поэтому попадает в начало файла, из-за чего файл кажется пустым.
Стоит ли удалять BOM перед парсингом?
Да. Когда сервер читает конфигурацию или парсит загруженные файлы, сначала удалите ведущий U+FEFF — replace(/^\uFEFF/, '') в Node, encoding='utf-8-sig' в Python — это гораздо дешевле, чем диагностировать это позже.