n8n: Can’t determine which item to use — как восстановить связь элементов
Workflow получает из узла Get Orders три заказа и должен отправить счёт только по тем, которые уже оплачены и готовы к отправке. Code node отбрасывает лишние записи и оставляет две. В следующем узле адрес письма берут выражением {{ $('Get Orders').item.json.email }}. Вместо адреса n8n показывает «Can’t determine which item to use»: для текущего результата нет однозначного пути назад к исходному заказу.
Данные заказа в n8n идут отдельными items. Пока узлы преобразуют их один к одному, платформа обычно может проследить происхождение результата. Но если Code node создаёт новый массив, меняет порядок или количество items, связь иногда надо указать явно. Для этого у выходного item есть поле pairedItem: индекс входного item, из которого он получен. Это не поле бизнес-данных в json, а служебная связь для последующих выражений.
Ситуация с тремя заказами
Пусть Get Orders отдаёт по порядку: заказ O-10 со статусом pending и адресом first@example.test, оплаченный O-11 с second@example.test, оплаченный O-12 с third@example.test. У последних двух стоит invoice_ready: true. Code node оставит O-11 и O-12. Их новые позиции в выходе — 0 и 1, но исходные позиции — 1 и 2. Если после фильтрации обратиться к first(), оба письма могут получить адрес первого, неготового заказа. Это уже ошибка доставки, даже если workflow перестал падать.
Поместите следующий код в Code node, режим Run Once for All Items, сразу после Get Orders. В этом примере у Code node один вход. Он сохраняет в выходе ID и сумму, а адрес позже берётся из соответствующего исходного item.
const source = $input.all();
const out = [];
for (let index = 0; index < source.length; index++) {
const order = source[index].json;
if (order.status !== 'paid' || order.invoice_ready !== true) continue;
if (typeof order.order_id !== 'string' || typeof order.total !== 'number') {
throw new Error('paid order lacks order_id or total');
}
out.push({
json: { order_id: order.order_id, total: order.total },
pairedItem: { item: index }
});
}
return out;
Для входа выше результат содержит два элемента: у O-11 будет pairedItem: { item: 1 }, у O-12 — pairedItem: { item: 2 }. В узле отправки используйте текущие $json.order_id и $json.total, а адрес возьмите через $('Get Orders').item.json.email. Так один выходной item соответствует одному получателю. Перед включением отправки посмотрите в preview обе пары ID–email: O-11 → second@example.test и O-12 → third@example.test.
Когда одного pairedItem недостаточно
Сообщение об ошибке сначала локализуйте: откройте выражение, в котором используется .item, и найдите первый узел между ним и источником, который поменял количество или состав элементов. Если это Code node, проверьте его выход и происхождение каждого результата. Если изменение произошло в Merge, связь может иметь несколько входов, и индекс без номера входа уже не описывает весь путь. Тогда укажите нужный источник при построении результата либо перенесите в json устойчивый бизнес-ID, по которому можно соединить записи явно.
При агрегации нескольких заказов в одно письмо нет единственного «того самого» исходного заказа. Выражение .item тогда концептуально не подходит: соберите адресата и список заказов по правилам бизнеса ещё до отправки. pairedItem помогает сохранить происхождение одного результата, но не выбирает, кому должен принадлежать итог объединения. Проверка на двух оплаченных заказах с разными адресами выявляет подмену first() сразу.
В платном курсе «Продвинутый n8n: production-автоматизации и AI-агенты» студент отрабатывает Merge, Code node и pairedItem на данных с несколькими items, затем проверяет workflow воспроизводимыми fixtures. В открытом уроке «Merge и потеря связей между items» можно увидеть ту же проблему на другой развилке. Откройте программу и пробный урок.
Для следующих сбоев полезны повтор failed execution после отправки, перенос workflow между средами и другие разборы production n8n.
