n8n-error-handling について
無人運用や API ワークフローを構築する n8n ユーザー向けに、失敗を可視化し、回復可能にする方法を解説します。ノード単位のエラー出力とワークフロー全体のエラー処理を扱います。
主な機能
- 01ノード単位のエラー出力設定
- 02ネットワークノードの再試行
- 03ワークフロー全体のエラー処理
- 04原因に応じた HTTP ステータス設定
- 05入力検証とエラー構造化
活用シーン
- 01Webhook API から適切なエラーを返す
- 02定期実行の失敗を通知する
- 03一時的なネットワーク障害から復旧する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ czlonkowski/ n8n-mcp --skill n8n-error-handlingインストール後、Claude Code で/n8n-error-handlingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
API_WORKFLOWS.mdERROR_WORKFLOWS.mdNODE_ERROR_OUTPUTS.mdREADME.mdRESPONSE_SHAPES.md詳細
n8n のエラー処理
デフォルトでは、n8n のノードでエラーが発生すると、ワークフロー全体が停止します。実行を監視している場合は、それで問題ありません。赤くなったノードを確認して修正できます。しかし、ウェブフック API、cron ジョブ、キューワーカー、エージェントのツールなど、無人で実行するものには適切なデフォルトではありません。呼び出し元にはタイムアウトや空の 500 エラーが返され、オペレーターにはアラートが届きません。その結果、「連携が突然動かなくなった」という症状が、ログも手掛かりもないまま発生します。
このスキルでは、障害を明確に、構造化して、復旧可能にし、理想的には自己修復できるようにして、一時的な不具合が人間に届かないようにする方法を説明します。
サイレント障害の大半を防ぐ考え方は、次の 2 つです。
- ノード単位のエラー出力 — ノードで障害が発生した場合、実行全体を停止させるのではなく、制御可能な 2 つ目の出力に処理をルーティングします。
- ワークフローレベルのエラーワークフロー — ノード単位の処理をすり抜けた障害(タイムアウト、ノード間のクラッシュ、未接続の障害など)をすべて捕捉して実行します。
実際に必要となるケース
| ワークフローの種類 | エラー処理の方針 |
|---|---|
ウェブフック/API(Respond to Webhook を含むものすべて) | 必須です。 エラーが起こり得る各ノードのエラー出力を接続し、原因に応じたステータスコードを返します。 |
| スケジュール実行/cron/キューワーカー/エージェントのツール(無人実行) | 必須です。 ワークフローレベルのエラーワークフローを設定し、ネットワークノードには retryOnFail を設定します。 |
| 自分で実行して監視する単発の内部ワークフロー | 任意です。 デフォルトの onError: "stopWorkflow" で問題ありません。赤くなったノードを確認して、再実行できます。 |
判断の分かれ目は、出力をあなた以外の誰かが見るかどうかです。下流システム、エンドユーザー、オンコールエンジニアのいずれかが見るのであれば、障害は無視するのではなく、処理する必要があります。監視するのが自分だけで、障害の影響が「気付いたら再実行する」程度であれば、緩やかな処理でも問題ありません。
最大のサイレントトラップ:ノード単位のエラー出力は 2 段階で設定する
n8n のワークフローがエラーを「処理」しているように見えながら、実際にはエラーを握りつぶしてしまう原因として、これが最もよくあります。ノードの障害をハンドラーにルーティングするには、2 つの変更が必要です。片方だけを行うと、設定が完了したように見えても正しく動作しません。
- ノードに
onError: "continueErrorOutput"を設定します。これにより 2 つ目の出力が作成されます。この設定がないと、何を接続してもmain[1]は存在しません。 - そのエラー出力(
connections.<node>.main[1]、つまりsourceIndex: 1)を実際のハンドラーに接続します。接続先がないと、エラーデータは行き場を失います。
どちらか一方だけを設定すると、次のような障害が起こります。
| 設定した内容 | 実行時の動作 |
|---|---|
onError を設定したが、エラー出力を接続していない | エラーデータはサイレントに破棄されます。下流のノードは実行されません。ダッシュボードでは実行が成功と表示されます。最悪の場合、エラーはどこにも記録されません。 |
エラー出力を接続したが、onError を設定していない | 出力スロットが実行されないため、ハンドラーに到達できません。障害が発生すると、ワークフローはそのまま停止します(デフォルトは stopWorkflow)。 |
| 両方を設定した | 障害時に main[1] を通じてハンドラーにルーティングされます。✅ |
n8n_update_partial_workflow で両方を設定する
// 1) Turn on the error output (creates main[1])
{ type: "updateNode", nodeName: "HTTP Request",
changes: { onError: "continueErrorOutput" } }
// 2) Wire the error output to a handler. sourceIndex: 1 = the error output.
{ type: "addConnection",
source: "HTTP Request",
target: "Handle Error",
sourceIndex: 1 }
sourceIndex: 0 は成功パス、sourceIndex: 1 はエラーパスです。(IF ノードでは branch: "true"/"false" のエイリアスがそれぞれインデックス 0/1 に対応します。一般的な、エラーが起こり得るノードでは、明示的に sourceIndex: 1 を使用してください。)
続いて検証します。 このトラップは validate_workflow では検出されません。エラー出力が不完全に接続されていても、検証は問題なく通ります。n8n_get_workflow でワークフローを取得し、次の両方が設定されていることを確認してください。
- ノードの
onErrorが"continueErrorOutput"になっている。 connections["HTTP Request"].main[1]にハンドラーが含まれている。
有効な onError の値:
| 値 | 効果 |
|---|---|
"stopWorkflow"(デフォルト) | エラーが発生すると、ワークフロー全体が停止します。 |
"continueRegularOutput" | エラーアイテムが通常の出力に流れます。まれなケースで、通常は適切ではありません。下流にはエラー形式のデータが渡され、そのまま処理が続行されます。 |
"continueErrorOutput" | エラーアイテムが別個のエラー出力(main[1])に流れます。接続するのはこちらです。 |
障害モードの一覧、ファンイン/ファンアウトの構成、検証方法については、NODE_ERROR_OUTPUTS.md を参照してください。
まずは自己修復:エラーパスをつなぐ前に retryOnFail を設定する
エラー分岐を作る前に、一時的な障害を吸収して、分岐まで届かないようにします。ネットワークサービスを呼び出すすべてのノード(HTTP Request、通信(Gmail/Slack/Discord)、データベース、AI ノード、サードパーティ連携など)で、ノードレベルのリトライを設定します。
{ type: "updateNode", nodeName: "HTTP Request",
changes: {
retryOnFail: true,
maxTries: 3,
waitBetweenTries: 5000 // ms
} }
これを最初に行う理由:429 や上流での一時的な不具合はリトライされ、通常は自動的に解消します。これにより、エラー出力が実行されるのは実際に継続している障害だけになります。そのため、5xx レスポンスやオンコールアラートには、ノイズではなく本当の問題が反映されます。
エンジンの制限も把握しておきましょう。リトライはあらゆるエラーで実行され(ステータスコードごとのフィルターはありません)、maxTries の上限は 5、waitBetweenTries の上限は 5000ms です。そのため、5000 は上限であると同時に妥当なデフォルト値でもあります。ノード固有の注意点については、n8n-node-configuration(NODE_FAMILY_GOTCHAS.md)を参照してください。
API ワークフロー:標準的な構成
呼び出し元に応答する Webhook トリガーのワークフローには、何よりも優先されるルールがあります。分岐を宙に浮かせないことです。成功時もすべてのエラー時も、あらゆるパスの末尾は Respond to Webhook にする必要があります。そうしないと、呼び出し元はタイムアウトするまで待ち続けます。
Webhook (responseMode: "responseNode")
├── validate input → process → Respond (200, body)
└── (any fallible node's error output → sourceIndex 1)
→ Respond (4xx/5xx, structured error body)
→ optional: log full error privately / notify
これを機能させるポイントは 3 つあります。
- 複数の分岐を 1 つのエラーレスポンダーに集約します。 エラーが発生し得る複数のノードから、
main[1]を単一のRespondノードに接続できます。グラフを読みやすく保てます。 - バリデーションエラー(4xx)はエラー出力ではなく、上流でチェックします。 必須フィールドがないことは、ノードのクラッシュではなく、応答が決まっている想定内の結果です。IF/Switch(または後述のスキーマバリデーター)で分岐し、400/401/403/404 を直接返します。エラー出力は、予期しない障害(5xx)に使用します。
- エラー分岐でも
responseCodeのデフォルト値は 200 です。 これも見落としやすい落とし穴です(RESPONSE_SHAPES.md と n8n-node-configuration NODE_FAMILY_GOTCHAS.md を参照)。エラー分岐がエラーボディとともに 200 を返すと、呼び出し元の HTTP クライアントには成功として見えるため、エラーハンドリングが実行されません。すべての Respond ノードでresponseCodeを明示的に設定してください。
入力バリデーション:Set ノードのスキーマバリデーター
構造化された入力バリデーションを行うエンドポイントでは、フィールドごとに IF/Switch ノードを連ねるのではなく、単一の Set ノード内で IIFE としてチェックを実行します。1 つのノードでペイロード全体を検証し、{ valid, validationError, details, requiredSchema } を返します。さらに、IF で valid に応じて分岐し、ロジック(200)に進むか、スキーマを呼び出し元に返して自身で修正できるようにする 400 Respond に進むかを決めます。Code ノードとサブワークフローで再帰的なバリデーターを使うよりも、はるかに高速です。パターン全体、制約のガイド、式のエスケープに関する注意点については、API_WORKFLOWS.md を参照してください。
レスポンス形式:原因 → ステータスコードの対応
text/plain "Internal Server Error" を返す 5xx は、技術的にはエラーレスポンスですが、実用上は役に立ちません。また、すべての失敗が 5xx になるわけではありません。リクエストが失敗した 理由 にステータスコードを合わせてください。呼び出し元はコードに応じて処理を分岐するためです。監視では 5xx(あなた側の問題)に対してアラートが発生しますが、4xx(呼び出し元側の問題)では発生しません。また、5xx は「再試行」を示唆し、4xx は「再試行しない」ことを示唆します。
よくある間違い: 不正な入力も含め、すべてを 500 internal_error を返す 1 つの Respond に接続することです。すると、呼び出し元は自身のバグとあなたの障害を区別できず、エラー率でも実際のインシデントとクライアント側のノイズを切り分けられません。
| 原因 | ステータス | error コード | 処理する場所 |
|---|---|---|---|
| 必須フィールドがない/型が違う | 400 | validation_error | 上流のチェック(スキーマバリデーター/IF)。エラー出力では処理しない |
| 認証情報がない、または無効 | 401 | unauthorized | 上流のチェック |
| 認証済みだが許可されていない | 403 | forbidden | 上流のチェック |
| リクエスト内のリソース ID は有効だが、データに存在しない | 404 | not_found | ルックアップの 結果 に応じて分岐する。エラーでは分岐しない |
| 現在の状態と競合する(重複、競合状態) | 409 | conflict | ロジックで検出する |
| 呼び出し元がレート制限を超過した | 429 | rate_limit_exceeded | Retry-After ヘッダーを設定する |
| ノードが例外をスローし、原因が不明 | 500 | internal_error | エラー出力経路 |
| サードパーティ API がエラーを返した | 502 | upstream_error | HTTP ノードのエラー出力 |
| 現時点では処理できない(下流が停止中) | 503 | service_unavailable | 特定のエラーを検出し、再試行を促す |
| サードパーティ API がタイムアウトした | 504 | upstream_timeout | メッセージでフィルタリングしたエラー出力 |
つまり、処理フローは 2 種類あります。4xx は処理開始前に判断します(IF/Switch +専用の Respond)。5xx はエラー出力から返します(「試した結果、失敗した」)。
Respond は 1 つにして、コードは式で決めます。 エラー経路の違いが 番号とメッセージ だけの場合(同じボディ形式、同じヘッダー)は、Switch を使って複数の Respond ノードに分岐させないでください。Respond ノードでは Response Code とボディの両方に式を使えるため、コードをインラインで計算します。
// Response Code field on a single Respond to Webhook:
{{ (() => {
const msg = $json.error?.message || $json.message || '';
if (msg.includes('INVALID_ID')) return 400;
if (/429|too many/i.test(msg)) return 429;
if (/timeout/i.test(msg)) return 504;
if (/upstream|llm|api/i.test(msg)) return 502;
return 500;
})() }}
Switch +複数の Respond を使うのは、経路の 構造 が異なる場合(ヘッダーが異なる、ボディ形式が異なる、リダイレクト)に限ります。形式が同じで番号だけ異なるなら、式で制御する Respond を 1 つ使います。
標準のエンベロープは { "error": "<code>", "message": "<human text>" } です。HTTP ステータスが成功か失敗かをすでに示すため、ok: false フラグは不要です。内部情報(スタックトレース、SQL、上流のレスポンスボディ、トークン)を絶対に漏らさないでください。そうした情報は非公開でログに記録し、サニタイズしたメッセージを返します。相関 ID、retry_after、バリデーションの details、および漏えいさせてはならない情報の一覧は、RESPONSE_SHAPES.md に記載されています。
ワークフローレベルのエラーワークフロー(すべてのエラーを捕捉)
ノードごとの出力では、想定していて、配線しておいたノードの失敗に対応できます。エラーワークフローは、それ以外のすべてを捕捉します。配線し忘れたノード、ノード間でのクラッシュ、ワークフロー全体のタイムアウト、トリガーの失敗などです。無人で実行するワークフローでは、「気づかないうちに停止した」を「アラートが届いた」に変える安全網になります。
Error Triggerノードから始まる、独立したワークフローとして作成します。n8n は失敗時のコンテキストを渡して、このワークフローを呼び出します。
{
"execution": { "id": "...", "url": "...", "lastNodeExecuted": "Fetch order",
"error": { "name": "NodeApiError", "message": "...", "timestamp": 1715000000000 } },
"workflow": { "id": "...", "name": "Sync Stripe customers" }
}
最小構成は、捕捉 → 通知です。
Error Trigger → Set (build alert from execution + error) → Slack/email (post to #incidents)
適切なアラートには、ワークフロー名、エディターへのリンク、失敗した実行へのリンク、失敗したノード名、そして実際のエラーメッセージ(「ワークフローに失敗しました」ではありません)を含めます。フィールド式と、オプションの「n8n ノード経由で失敗した入力を取得する」拡張については、ERROR_WORKFLOWS.mdをご覧ください。
あらかじめ注意しておきたい落とし穴が2つあります。
- 再帰の落とし穴。 エラーワークフローが Slack に通知し、Slack が停止していると、エラーワークフローも失敗し、元のエラーが消えてしまいます。監視対象のワークフローとは別のチャネルで通知してください(多くのワークフローが Slack に通知するなら、エラーワークフローはメールを使います)。また、通知に失敗しても記録が残るよう、フォールバック(Data Table への書き込み)を追加してください。
- 「処理済み」のエラーは上位に伝播しません。 ノードのエラー出力を、データを破棄するだけの何もしないノードにつなぐと、n8n はエラーを処理済みと見なし、エラーワークフローを実行しません。エラーを使って実際に何かを行う場合に限り、ノードごとにエラーを捕捉してください。
コミュニティ MCP ではできないこと: エラーワークフローの割り当て(インスタンスのデフォルトまたはワークフローごとの上書き)は、n8n のUI 設定です(Workflow Settings → Error Workflow)。これを設定する MCP ツールはありません。MCP でエラーワークフローを作成したら、ユーザーに正確な UI 操作手順を伝え、無人で実行する各ワークフローで同じ設定を繰り返すか、インスタンスのデフォルトを設定するよう案内してください。
コミュニティ MCP では利用できない機能
| やりたいこと | 実際のところ |
|---|---|
| ワークフローのエラーワークフロー設定を行う | UI のみ(Workflow Settings → Error Workflow)。MCP ツールはありません。ワークフローを作成してから、ユーザーに UI での操作手順を伝えてください。 |
| その他のワークフロー設定(Save Execution Data、タイムゾーン、タイムアウト、呼び出し元のポリシー)を切り替える | UI のみです。n8n_update_partial_workflow には updateSettings がありますが、エラーワークフローの割り当てが確実に公開されているわけではありません。UI で確認してください。 |
| インスタンス全体のエラーロギング(Sentry、サーバーログ)を有効にする | インスタンス設定が必要です。n8n ワークフローの範囲外です。 |
MCPでできること:エラーワークフローの作成、ノードの onError/retryOnFail の設定(updateNode/patchNodeField)、エラー出力の接続(sourceIndex: 1 を指定した addConnection)、検証(validate_workflow、n8n_validate_workflow)、よくある問題の自動修正(n8n_autofix_workflow)、テスト(n8n_test_workflow)、失敗の確認(n8n_executions)。
アンチパターン
| アンチパターン | 問題点 | 対処法 |
|---|---|---|
onError が設定されているが、エラー出力が接続されていない | エラーが黙って破棄され、実行が成功として表示されます | sourceIndex: 1 を実際のハンドラーに接続するか、onError を stopWorkflow に戻してエラーが明示されるようにします |
エラー出力は接続されているが、onError が設定されていない | スロットが作動せず、ハンドラーに到達できず、失敗時にワークフローが停止します | onError: "continueErrorOutput" を設定します |
| Webhook → 処理 → 応答で、エラーブランチがない | 呼び出し元がタイムアウトするか、n8n の汎用 500 エラーを受け取ります | エラーが発生し得るすべてのノードのエラー出力を Respond に接続します |
エラーブランチが {error} 本文とともに 200 を返す | 呼び出し元のクライアントが成功と判断し、エラーハンドリングが実行されません | エラー時の Respond では responseCode に 4xx/5xx を明示的に設定します |
すべてのエラーに対して 500 internal_error を返す | 呼び出し元が、不正な入力とサービス側の障害を区別できません | 原因をステータスに対応づけます(呼び出し元側は 4xx、サービス側は 5xx) |
| Code ノードでエラーを捕捉し、データとして返す | 下流がエラー形式のデータを処理して続行します | エラーをスローさせ、onError: "continueErrorOutput" と接続済みのパスを使います |
retryOnFail が設定されていないネットワークノード | 一時的な 429 や瞬断のたびに 5xx が発生し、不要なアラートが鳴ります | retryOnFail: true, maxTries: 3, waitBetweenTries: 5000 |
| ステータスコードだけが異なる複数の Respond への Switch | 1 つの Respond で済む処理に 5 つのノードが必要になります | 1 つの式駆動型 Respond でコードをインライン計算します |
| エラーワークフローのない無人ワークフロー | 実際に障害が発生しても処理されません | Error Trigger ワークフローを作成し、UI で割り当てます |
| ワークフローが監視しているのと同じチャネルにエラーワークフローが通知する | チャネルが停止するとエラーワークフローも失敗し、エラーが消失します | 別のチャネルを使い、Data Table にもフォールバックします |
$json.error(スタックトレース/SQL/トークン)を応答に漏らす | 呼び出し元や攻撃者に内部情報が公開されます | 非公開でログに記録し、サニタイズしたメッセージを返します |
参照ファイル
| ファイル | 参照するタイミング |
|---|---|
| NODE_ERROR_OUTPUTS.md | エラーが発生し得る個々のノードで、ノード単位のエラー出力を接続するとき |
| API_WORKFLOWS.md | スキーマバリデーターを含む、Webhook → Respond ワークフローを構築/レビューするとき |
| RESPONSE_SHAPES.md | 応答本文の規約やステータスコードを定義し、漏らしてはいけない情報を確認するとき |
| ERROR_WORKFLOWS.md | 無人ワークフロー向けに、ワークフローレベルの包括的なエラー捕捉を設定するとき |
他のスキルとの連携
- n8n-workflow-patterns — Webhook/API とスケジュール実行のパターンは、エラーハンドリングが関わる箇所です。全体の形にはこちらを使い、堅牢化にはこのスキルを使います。
- n8n-node-configuration —
onError/retryOnFailはノード設定です。NODE_FAMILY_GOTCHAS.md では、Webhook/Respond のレスポンスコードに関する落とし穴を詳しく説明しています。 - n8n-validation-expert — エラー出力の接続が不完全(2 つの手順のうち 1 つが欠けている状態)なのは、接続/設定の監査項目であり、バリデーションエラーではありません。このスキルで修正します。
- n8n-expression-syntax — 式駆動型の
Response Codeとアラートメッセージの式は、正しい{{ }}構文と$json.errorへのアクセスに依存します。 - n8n-code-javascript / n8n-code-python — Code ノード内でエラーを捕捉する場合は、意図を明確に決めてください。エラー出力を使うために再スローするか、処理して続行します。エラー形式のデータを返して、成功したかのように扱わないでください。
- n8n-code-tool — エージェントの Code Tool はスローされたエラーを LLM に返し、LLM はそれを受けて再試行します。これはワークフローノードとは異なるエラー処理の契約です。
- n8n-binary-and-data — ファイル/バイナリー操作でもエラーは発生し得るため、ネットワークノードと同様にエラー出力を接続します。
クイックリファレンスチェックリスト
API/Webhook ワークフローの場合:
- Webhook トリガーで
responseMode: "responseNode"を使用する - 入力を上流で検証する → 4xx を返す Respond(スキーマバリデーターまたは IF)
- 失敗する可能性のあるすべてのノードに
onError: "continueErrorOutput"を設定し、かつmain[1]を接続する - ネットワークノードに
retryOnFail: true, maxTries: 3, waitBetweenTries: 5000を設定する - エラーパスの最後に、
responseCodeを明示的に 4xx/5xx に設定した Respond を置く - 原因に合ったステータスコードを使う(呼び出し元の問題は 4xx、自分側の問題は 5xx)
- エラーボディは
{ error, message }とする — スタックトレース、SQL、トークンは含めない -
n8n_get_workflowで確認する:失敗する可能性のある各ノードにonErrorとmain[1]がある
無人(スケジュール/cron/キュー)ワークフローの場合:
- ネットワークノードに
retryOnFailを設定する - Error Trigger ワークフローを用意する(捕捉 → 通知、必要に応じて再試行)
- エラーワークフローは別のチャネルで通知し、フォールバックも用意する(再帰の罠を防ぐ)
- n8n UI でエラーワークフローの設定を割り当てる(MCP では設定できないため、ユーザーに伝える)
覚えておいてください:デフォルトは何も通知されないことです。エラー処理には 2 つの対応が必要です — 失敗をルーティングし(ノードごとの onError と接続済みの出力、または包括的なエラーワークフロー)、そして伝える(事実を示すステータスコードとボディを返す)。片方だけでは、何もないより悪い結果になります。完了したように見えるためです。