Категории в YML-фиде: как найти ошибки categoryId и parentId
YML-фид может быть корректным XML, но содержать неправильные связи товаров с категориями. Например, у смартфона указан categoryId, которого нет в справочнике. Или категория существует, но её родитель потерялся при выгрузке.
Проверять нужно две части файла: categoryId внутри товара и отдельный блок categories. Ниже — как сопоставить их, найти сломанную ветку и проверить большой каталог без ручного чтения тысяч предложений.
Как связаны categories и categoryId
categoryId — ссылка на идентификатор категории магазина. Его берут из того же справочника, из которого генератор формирует categories: например, из таблицы разделов CMS. Это не название раздела и не автоматически выданный Яндексом номер.
Внутри shop связь выглядит так. Это фрагмент: остальные поля товара опущены.
<categories>
<category id="1">Электроника</category>
<category id="10" parentId="1">Смартфоны</category>
</categories>
<offers>
<offer id="123">
<name>Смартфон, 128 ГБ</name>
<categoryId>10</categoryId>
</offer>
</offers>
Товар 123 ссылается на категорию 10 — «Смартфоны». Её parentId="1" ведёт к «Электронике». У корневой категории родителя нет. Элементы category при этом лежат рядом: вложенность разделов задаёт атрибут parentId, а не вложенные XML-теги.
Какие правила действуют у сервисов Яндекса
Для товарного YML в Яндекс Директе обязателен ровно один categoryId в каждом offer: положительное целое число длиной до 18 знаков. Блок categories размещают перед offers. Если товар состоит в нескольких разделах CMS, генератору нужно выбрать одну категорию для этой выгрузки. Остальные поля разобраны в статье про YML-фид для Директа.
В Яндекс Товарах categoryId также обязателен и указывает на запись в categories. Справка по категориям требует уникальных названий и ID; идентификаторы — положительные целые числа до 18 символов, без начального нуля. Для распределения в Поиске учитываются названия всей цепочки родителей. Ограничение «один categoryId» прямо сформулировано в справке Директа; не переносите его молча на другие форматы.
У Маркета набор обязательных блоков зависит от задачи: categories нужен для управления товарами, но не для отдельной выгрузки параметров размещения. ID категорий уникальны, числовые, положительные, до 18 цифр и без ведущего нуля; иерархию задаёт parentId. В текущей инструкции по параметрам товара категория передаётся через market_category_id. Поэтому обязательность categoryId из Директа нельзя объявлять общим правилом любого YML для Маркета.
categoryId есть, а категории нет
Допустим, у товара стоит <categoryId>57</categoryId>, но в categories объявлены только разделы 1 и 10. Ссылка ведёт в пустоту. Совпадение числа с ID другой сущности, например товара, ничего не исправляет: нужна именно запись category.
Обычно причина находится в генераторе: категорию удалили из CMS, а старые привязки остались; товары и разделы выбрали из разных наборов данных; фильтр исключил раздел, но сохранил его товары. Сверяйте обе части одной сохранённой версии фида — два скачивания могут попасть на разные генерации.
Восстановите пропущенную категорию, если она должна выгружаться, либо переназначьте товары на правильный существующий раздел в источнике. Не подставляйте всем ошибочным товарам первую доступную категорию: проверка существования пройдёт, а привязка останется неверной. Конкретный результат обработки такой ошибки смотрите в отчёте получателя.
parentId ссылается на отсутствующего родителя
<category id="52" parentId="10">Ноутбуки</category>
Если записи id="10" нет, «Ноутбуки» существуют, но путь обрывается: «? → Ноутбуки» вместо «Электроника → Компьютеры → Ноутбуки». При выборочной выгрузке легко оставить только разделы с товарами и потерять промежуточные категории без собственных предложений.
Включите нужных предков в справочник. Убирать parentId стоит лишь тогда, когда раздел действительно должен стать корневым. Отдельно проверьте самоссылку id="52" parentId="52" и цикл: категория 10 ссылается на 52, а 52 — обратно на 10. Все ID могут существовать, но такая цепочка не заканчивается корнем.
Дубли ID и привязка по названию
<category id="10">Смартфоны</category>
<category id="10">Ноутбуки</category>
У одного ID два значения. По categoryId=10 уже нельзя однозначно определить раздел. Не рассчитывайте, что площадка выберет нужную запись. Исправьте повтор в источнике или таблице соответствий генератора и обновите ссылки затронутых товаров.
Название тоже не заменяет ID. Если «Смартфоны» переименовали в «Телефоны и смартфоны», связь продолжает строиться по числу 10. При простом переименовании удобнее сохранить прежний идентификатор. Если номер всё же меняется, согласованно измените categoryId товаров и parentId дочерних разделов.
Бывает и тихая ошибка: все ссылки существуют, но смартфон привязан к «Ноутбукам». Сравните назначение в CMS, таблицу соответствий и полную цепочку названий в XML. Проверка существования ID сама по себе не определяет, подходит ли раздел товару.
Как проверить категории в большом фиде
Файл на 80 МБ удобнее обработать потоковым XML-парсером, например XMLReader в PHP. Для проверки связей не нужны описания, цены и картинки. Алгоритм такой:
- Соберите
category/@idи парыid → parentIdтолько изshop/categories. При добавлении отмечайте дубли: обычный словарь может незаметно перезаписать предыдущую запись. - Пройдите
shop/offers/offer. Для каждогоcategoryIdпроверьте наличие в справочнике. Сохраните ID проблемного товара и значение ссылки. - Отдельно посчитайте отсутствующие и пустые
categoryId; проверяйте обязательность и количество элементов по выбранному формату. - Сверьте все непустые
parentIdсо справочником. Затем пройдите цепочки родителей, отмечая посещённые ID внутри каждой цепочки: повтор означает цикл. - Выведите количество ошибок и несколько конкретных примеров каждого вида, чтобы разработчик мог найти исходные записи.
Если справочник ещё не собран, отложите сверку ссылок до конца чтения или сделайте два потоковых прохода. Освобождайте прочитанные элементы; храните только справочник, счётчики и ограниченную выборку ошибок. Если даже категории не помещаются в память, индекс ID и связи родителей можно держать во временной SQLite-базе.
Условная сводка: 184 категории, 12 430 товаров, 7 товаров с неизвестным categoryId, 2 категории с отсутствующим родителем. Это пример диагностики, а не результат реальной проверки. Различайте число затронутых товаров и число неизвестных ID: на один потерянный раздел могут ссылаться сотни предложений.
В полной проверке ФидСторожа реализован поиск неизвестных ссылок categoryId, дублей ID категорий, отсутствующих родителей, самоссылок и циклов. Сервис показывает найденные ошибки; смысловую правильность назначения товара разделу нужно проверить по каталогу.
Если ошибка только у части товаров
Возьмите рабочий и проблемный offer из одного фида. Сравните их categoryId, соответствующие записи category и пути к корню. Общий отсутствующий родитель у проблемных товаров указывает на одну сломанную ветку, а разные неверные ID — на привязки или преобразование идентификаторов.
Если связи исправны, переходите к диагностике пропавших товаров. Ошибки других полей и общий порядок проверки собраны в разборе частых ошибок YML.
Быстрый чек-лист
- Обязательный
categoryIdзаполнен. - Каждая ссылка ведёт в
categories. - ID категорий уникальны.
- Все указанные родители существуют.
- Нет самоссылок и циклов.
- Цепочка названий соответствует товару.
- Формат ID и число элементов сверены с требованиями получателя.
Требования сверены с официальными справками Яндекса 8 сентября 2026 года. Ссылки на них приведены в разделе о различиях сервисов.