n8n Codeノードで最初のアイテムしか処理されない原因と直し方

n8nでアイテムを1件ずつ回しているのに、2件目以降も1件目の設定で処理されることがあります。エラーは出ないため、出力を見比べるまで気づきにくい不具合です。この記事では、弊社の本番で起きた例をもとに、原因と直し方をまとめます。
この記事の結論
- Codeノードで
$('ノード名').first()と書くと、いま処理しているアイテムに関係なく、そのノードが出した最初のアイテムが返ります。 - いま処理しているアイテムに対応するデータがほしいときは、
$('ノード名').item(Run Once for Each Item のとき)か、$('ノード名').itemMatching(i)(Run Once for All Items のとき)を使います。 - ノード設定の「Execute Once」がオンだと、そのノードは最初のアイテムだけで1回しか動きません。
- ループ(Loop Over Items)の中で
context.currentItemIndexを当てにしないでください。弊社では常に undefined でした。
実際に起きたこと
弊社で動かしているワークフローの1本は、複数のアカウントの動画をまとめて作っています。アカウントの一覧を Loop Over Items(旧名 Split In Batches)で1件ずつ回し、アカウントごとの設定を読んで、動画生成のAPIを呼ぶ作りです。
ある日、結果を記録する表に、動画のURLも進み具合を問い合わせるURLも空のレコードが7件たまっているのが見つかりました。自動の修復役がそれをエラー扱いに変えても、翌日にはまた新しい空のレコードができていました。
調べると、APIへ送る中身を組み立てるCodeノードが、設定を次のように読んでいました。
const config = $('Set_Config').first().json;
この書き方は、ループの中で常に1番目のアカウントの設定を返します。そのため、1番目のアカウントに参考画像があると、画像の中の崩れた文字を調べる処理が全アカウントで走る作りになっていました。崩れた文字が見つかると、送り先を「スキップ」を意味する値に書き換えます。その結果、参考画像を持たない別のアカウントまで巻き添えでスキップされました。
APIの呼び出しは不正な送り先で失敗しましたが、ノードは失敗しても先へ進む設定でした。そのため、問い合わせ用のURLが空のまま、結果のレコードだけが作られていました。空のレコードは重複の判定も狂わせ、そのアカウントがその日に投稿できなくなる流れができていました。
原因
.first() は「いまのアイテム」を見ない
n8nの公式ドキュメントは、.first() を「Returns the first item output by the node」と説明しています。n8n 本体のソース(n8n-workflow パッケージの workflow-data-proxy.js)でも、.first() は参照先ノードの出力を取り出して、その0番目を返すだけです。
if (executionData[0])
return that.returnExecutionData(executionData[0], resolveFullItem);
ここには、いま処理しているアイテムの番号が出てきません。読む対象は、実行の番号を省いた場合、参照先ノードの最後の実行の出力です。
runIndex = runIndex === undefined ? that.defaultReturnRunIndex : runIndex;
このため、ループの外で一度に全アカウント分のアイテムを出すノードを読む場合は、何周目でも1件目が返ります。参照先がループの中で周ごとに動くノードなら、その周の出力の1件目になります。
.item は「つながり(pairedItem)」をたどる
一方、.item は公式ドキュメントで「Returns the matching item, i.e. the one used to produce the current item in the current node.」と説明されています。pairedItem(ペアのアイテム)は、各アイテムが「前のノードのどのアイテムから作られたか」を覚えている印です。
ソースでも、.item は現在のアイテムの番号を使い、入力アイテムの pairedItem をさかのぼって、参照先ノードの対応するアイテムを探します。
itemIndex = that.itemIndex;
...
const pairedItem = input.pairedItem;
このため、ループの中でもアカウントごとに正しい設定が返ります。
Codeノードの2つのモード
Codeノードには「Run Once for All Items」と「Run Once for Each Item」の2つのモードがあり、既定は runOnceForAllItems です。前者はノードが1回だけ動き、全アイテムをまとめて受け取ります。後者はアイテムごとにコードが動きます。
「Run Once for Each Item」では、$input.first() などは使えません。使うと次のエラーで止まります。
Can't use .first() here
This is only available in 'Run Once for All Items' mode
ただしこの検査は $input. の書き方だけが対象です。$('Set_Config').first() のように別のノードを名指しした書き方は止められず、そのまま1件目を返します。
「Execute Once」がオンになっている
Codeノードに限らず、ノードの設定に「Execute Once」があります。画面の説明は「If active, the node executes only once, with data from the first item it receives」です。本体の実行部分(n8n-core の workflow-execute.js)でも、オンのときは入力を最初の1件に切り詰めています。
if (node.executeOnce === true) {
...
return input && input.slice(0, 1);
「最初のアイテムしか処理されない」ときは、まずこの設定を疑ってください。
直し方
.first() を使っている場所を探す
ループの中にあるノードで、$('ノード名').first() を使っている場所を全部洗い出します。1か所を見つけたら、同じワークフローの別のノードにも同じ参照がないかを確かめてください。弊社の記録でも、別のノードが同じ問題を抱えている可能性を挙げています。
本当に1件目がほしい場面(全アカウント共通の設定を1件だけ持つノードなど)では、.first() のままで問題ありません。直す対象は「アイテムごとに値が違うはずのノード」を読んでいる場所です。
Run Once for Each Item なら .item に置き換える
アイテムごとに動くモードでは、.first() を .item に置き換えます。
// モード: Run Once for Each Item
// 直す前: const config = $('Set_Config').first().json;
const config = $('Set_Config').item.json;
return {
json: {
...$input.item.json,
client_id: config.client_id,
},
};
Run Once for All Items なら itemMatching(i) を使う
全アイテムをまとめて扱うモードでは、何番目のアイテムかを自分で渡します。公式ドキュメントでは .itemMatching() を「Returns the matching item, i.e. the one used to produce the item in the current node at the specified index.」と説明しています。
// モード: Run Once for All Items
const items = $input.all();
const out = [];
for (let i = 0; i < items.length; i++) {
const config = $('Set_Config').itemMatching(i).json;
out.push({
json: { ...items[i].json, client_id: config.client_id },
pairedItem: { item: i },
});
}
return out;
最後の pairedItem は、後ろのノードが .item でたどれるようにするための印です。公式ドキュメントにも「To control item linking, set pairedItem when returning data.」とあります。新しいアイテムを作って返すCodeノードでは、これを付けておくと後で困りません。
context.currentItemIndex を使っている場所も直す
ループの何周目かを context.currentItemIndex で知ろうとするコードも、弊社では動きませんでした。Loop Over Items の中では常に undefined でした。ここも $('ノード名').item.json の形に置き換えます。
空の結果を記録しないガードを足す
弊社の記録では、本来の直し方は .first() を .item に変えることだとしています。ただし、別のノードにも同じ参照がある可能性があるため、慎重に進めるとしました。そこで弊社が先に入れたのは、問い合わせ用のURLが空のときはレコードを作らないガードです。参照の誤りが残っていても、空のレコードが増えて次の処理を狂わせることは止められます。
if (!statusUrl) {
return [{ json: { saved: false, skipped: true, reason: 'no_status_url' } }];
}
保存したら反映させる
APIでワークフローを書き換えた場合は、保存しただけでは動いている版に反映されないことがあります。弊社では deactivate してから activate し直しています。詳しくは「n8nのAPIでワークフローを更新する方法と、反映されない・止まらない原因」に書きました。
直ったかを確かめる
- テスト用のコピーで、設定の違うアイテムを複数流します。1件だけでは、
.first()と.itemの違いが出ません。 - 実行結果の画面で、ループの各周のCodeノードの出力を開き、
client_idなどアイテムを見分ける値が周ごとに変わっているかを見ます。 - 記録先の表に、空のレコードが新しく増えていないかを数日見ます。弊社の例では、症状は「毎日新たに生成される」形で出ていました。
それでも直らないとき
.item に替えたあと、次のようなエラーが出ることがあります。
Paired item data for item from node 'ノード名' is unavailable. Ensure 'ノード名' is providing the required output.
これは、途中のノードが pairedItem を付けずにアイテムを返したときに出ます。途中にあるCodeノードの戻り値に、上の Run Once for All Items の例のように pairedItem を付けてください。
「No path back to referenced node」と出る場合は、参照しているノードが、いまのノードの前に線でつながっていません。.item は線をさかのぼってたどるため、つながっていないノードは読めません。つなぎ方を見直すか、別の経路で値を渡してください。
コード上は正しいのに1件目しか動かないときは、ノードの設定画面で「Execute Once」がオフになっているかをもう一度確かめてください。
まとめ
$('ノード名').first()は、いまのアイテムに関係なく参照先の最初のアイテムを返します。- アイテムごとの値は、Run Once for Each Item なら
.item、Run Once for All Items なら.itemMatching(i)で読みます。 - 新しいアイテムを返すCodeノードには
pairedItemを付け、後ろのノードがたどれるようにします。 - 「Execute Once」がオンだと、ノードは最初のアイテムだけで1回しか動きません。
- 確かめるときは、設定の違うアイテムを複数流します。
参考にした公式ドキュメント






