中級向け
n8n Execute Sub-workflowの使い方:宣言していない項目は黙って消える
ワークフローを分割して呼び出すノードです。once と each で子の実行数が変わること、入力を宣言すると宣言外の項目が届かないこと、each の直後に return $input.all() が落ちる理由を実際に動かして確かめました。
公開
動作確認: — n8n 2.36.8 / Execute Sub-workflow ノード v1.3 / Execute Workflow Trigger v1.2
Execute Sub-workflow は、別のワークフローを呼び出すノードです。
同じ処理を何本ものワークフローに書いているとき、共通部分を切り出して1本にまとめられます。 通知の送り方、ログの残し方、データの整形。直したいときに1箇所で済むのが利点です。
ただし呼ぶ側と呼ばれる側でデータの受け渡し方に決まりがあり、ここを知らないと データが消えます。親子2本のワークフローを作って確かめました。
呼ぶ側と呼ばれる側
2つのノードが対になっています。
| 役割 | ノード |
|---|---|
| 呼ぶ側(親) | Execute Sub-workflow |
| 呼ばれる側(子) | Execute Workflow Trigger |
子の先頭に Execute Workflow Trigger を置くと、そのワークフローは「呼ばれる用」になります。
once と each で子の実行数が変わる
親のノードには Mode があります。

3件のデータを流して、それぞれで試しました。
| Mode | 子が受け取る件数 | 子の実行回数 |
|---|---|---|
| Run once with all items(既定) | 3件まとめて | 1回 |
| Run once for each item | 1件ずつ | 3回 |
子は別の実行として記録される
子は親とは別の実行として履歴に残ります。実行データを見ると、
mode が integrated になっていました。
{ "id": "77", "workflowId": "BAySRuvDoyrhBRw0",
"status": "success", "mode": "integrated" }
手動実行なら manual、Webhook なら webhook です。integrated は「他から呼ばれた」印で、
これで見分けられます。
each のときは、親に返ってくるアイテムに子の実行IDが付いていました。
"metadata": { "subExecution": { "executionId": "79", "workflowId": "BAySRuvDoyrhBRw0" } }
どのアイテムがどの子実行に対応するかを辿れます。
each の直後に return $input.all() を書くと落ちる
この metadata が、そのまま落とし穴になりました。
each で呼んだ直後に Code ノードを置き、return $input.all(); と書いたところ、
ワークフローが止まりました。
Invalid output format [item 0]
An output item contains the reserved key `json`.
対処は、json だけ取り出して返すことです。
// metadata を落として json だけ返す
return $input.all().map(i => ({ json: i.json }));
これで通ることを確認しました。
入力を宣言すると、宣言していない項目は消える
ここが一番はまるところです。
子の Execute Workflow Trigger には Input data mode という設定があり、 3つから選べます。
| 表記 | 何をするか |
|---|---|
| Define using fields below(既定) | 受け取る項目を1つずつ宣言する |
| Define using JSON example | 例のJSONから項目を推測させる |
| Accept all data | 親から来たデータをすべてそのまま受け取る |
親からは id / name / memo の3項目を送りました。
子で id と name だけを宣言した状態で実行した結果です。
// 子が受け取った内容
{ "id": 1, "name": "田中" }
memo が消えています。
全部そのまま渡したいなら Accept all data を選びます。
この設定で実行したときは、memo も含めて3項目とも届きました。

子で項目を宣言すると、親側にその項目の入力欄が出ます。ここに何を渡すかを式で書く形です。
待たない設定では、子の結果が返らない
Options に Wait For Sub-Workflow があり、既定はオンです。
これをオフにして実行したところ、親に返ってきたのは子の処理結果ではなく、 子へ渡す前の入力そのものでした。
// 待たない設定のとき、親に返ってきたもの
{ "id": 1, "name": "田中", "memo": "宣言しない項目" }
子が何を返したかに関係なく、入力がそのまま素通しされます。
使い分けの目安
- 共通処理を切り出すのが主な用途。直す場所が1箇所になります
- Mode は基本 once。 each は実行履歴が件数ぶん増えます
- 項目を宣言するか、Accept all data にするかは最初に決める。 後から項目が増えたとき、 宣言方式だと子側の修正を忘れて消えます
- each の直後の Code ノードでは
$input.all()をそのまま返さない
検証していないこと
- Source は
Database(保存済みのワークフローをIDで指定)だけ試しました。 JSONを直接渡す方式やURLから読む方式は動かしていません Define using JSON exampleは試していません。 宣言方式と Accept all data の2つだけです- 子でエラーが起きたときに親がどうなるかは確認していません。 これは別途確かめる価値があります
- 子から親へ戻る値の形は、子の最後のノードの出力がそのまま返ることを確認しただけです。 複数ノードに分岐しているときの挙動は見ていません
- 検証はすべて手動実行です
Input data modeの選択肢の表記は、画面ではなくノード定義の表示名から読み取りました。ModeとWait For Sub-Workflowは画面で確認しています
「親では入っているのに子で消える」 が、このノードで一番多い詰まり方だと思います。 原因は入力の宣言です。
- ワークフローの実行単位は n8n 用語集 に
- 失敗時の通知は n8n のエラー通知は、手動実行では飛ばない
- Code ノードの返し方は Codeノードの使い方