关于 n8n-error-handling-official
为使用 n8n 的 Agent 提供工作流错误处理规范,涵盖 Webhook API 和无人值守流程。重点是结构化错误响应、节点级重试与工作流级错误捕获。
主要功能
- 01配置节点错误输出
- 02按原因映射 HTTP 状态码
- 03为网络节点设置重试
- 04配置工作流级错误流程
- 05使用 Set IIFE 校验输入
适用场景
- 01构建带错误响应的 Webhook API
- 02为定时或队列流程捕获故障
- 03区分调用方错误与上游故障
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ n8n-io/ skills --skill n8n-error-handling-official安装后在 Claude Code 中输入/n8n-error-handling-official确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/API_WORKFLOWS.mdERROR_WORKFLOWS.mdNODE_ERROR_OUTPUTS.mdRESPONSE_SHAPES.mdreferences/examples/validation-subworkflow-usage.tsvalidation-subworkflow.ts详细介绍
n8n 错误处理
n8n 节点的默认行为:发生错误 → 工作流停止 → 调用方得不到任何有用信息。对于无人值守的工作流(Webhook API、计划任务、队列工作进程)来说,这种默认行为并不合适。症状就是“集成突然停止工作”,却没有日志、消息或线索。
本技能介绍如何处理错误,让故障清晰可见、结构化且可恢复。理想情况下,还能以自动修复的方式处理故障。
不可妥协的要求
对于任何API 形态的工作流(Webhook 触发器搭配 Respond to Webhook):
- 每个可能失败的节点都要连接错误输出,并且两条路径最终都要到达
Respond to Webhook。 不要留下悬空的错误分支,否则调用方会遇到超时。“可能失败”指 HTTP、数据库、第三方 API、文件操作以及任何可能抛出错误的操作。 - 状态码要对应故障原因。 调用方的错误 → 4xx;你这边的错误 → 5xx。在错误路径上默认返回 200 会造成无声故障:调用方以为成功了,却处理了空数据。
对于任何无人值守的工作流(计划任务、cron、队列驱动、Agent 工具):
3. 设置工作流级错误工作流。 捕获节点级处理未能处理的错误:超时、节点之间的崩溃、未连接错误输出的节点发生的错误。通过 update_workflow setWorkflowSettings.errorWorkflow 设置(n8n 2.29.0+);目标工作流必须是已发布且包含激活状态的 Error Trigger 的工作流,否则更新会被拒绝。参见 references/ERROR_WORKFLOWS.md。
强烈建议的默认做法
- 错误响应正文应采用结构化格式。 不要只返回“Internal Server Error”。请使用
{ "error": "<short identifier>", "message": "<human-readable>" }。参见references/RESPONSE_SHAPES.md。 - 配置调用网络的节点的
retryOnFail。 瞬时 429 和上游短暂故障会在到达错误路径前得到处理。参见下文“针对瞬时故障的自愈”。
何时可以放宽错误处理要求
仅供内部使用的一次性工作流,只有你一个用户、你会检查每次运行,并且故障的代价只是“我发现后重新运行”。默认的 onError: 'stopWorkflow' 就可以。判断标准是:如果除了你以外,还有其他人会看到输出(下游系统、最终用户、值班人员),就必须遵守不可妥协的要求。
API 工作流结构
标准的 Webhook API 工作流:
Webhook trigger
├── (success path) → Process → Respond to Webhook (200, body)
└── (any node's error output)
→ Respond to Webhook (5xx, structured error body)
→ Optional: log to error tracker / logger / notify channel
如需了解如何将多个可能失败的节点连接到同一个错误响应节点,请参见 references/API_WORKFLOWS.md 中的完整操作指南。
架构验证器(Set IIFE)
对于任何需要验证输入的 Webhook API,应将基于 Set 的架构验证器模式嵌入端点,而不是为每个字段编写 IF/Switch 链。以下两个示例文件是权威参考:
references/examples/validation-subworkflow.ts:基础模式(Webhook → Set(含验证 IIFE)→ Respond,状态码由表达式驱动)。适合作为最简演示。references/examples/validation-subworkflow-usage.ts:端点模式(Webhook → Set → If valid → 业务逻辑 → 200 成功响应 / 400 响应,使用标准{error: "validation_error", message, details, request_schema}正文)。将此模式嵌入端点,并用实际逻辑替换 NoOp 占位符。
使用此模式的 Agent 操作步骤:
- 将用法示例的结构嵌入新端点。 Webhook → Set(Validate Schema)→ If Params Valid → 业务逻辑 → success/400 Respond。不要另起炉灶。
- 根据你的架构编辑 IIFE。 为端点的输入结构更新
REQUIRED_SCHEMA以及 Set 节点表达式中的逐字段检查。架构常量下面的模式是机械式的:存在性检查、类型检查、约束检查、将错误推入errors[]。 - 不要更改输出结构。
valid、validationError、details、requiredSchema是 Respond 节点使用的契约。重命名会破坏响应正文。
完整操作步骤、支持的约束模式、架构设计规则,以及 ={{ ... }} 包装时需要注意的问题,见 references/API_WORKFLOWS.md 中的“Schema validator (Set IIFE)”。
每个节点的错误设置(回顾)
每个可能失败的节点都需要进行两项更改(参见 references/NODE_ERROR_OUTPUTS.md):
- 在节点配置中设置
onError: 'continueErrorOutput'。 - 将
output(1)连线至错误处理器。
两项都必须设置。只设置其中一项会导致错误被静默处理。
瞬时故障时的自我恢复
连接错误路径之前,请先为所有会发起网络调用的节点配置节点级重试(HTTP Request、Gmail/Slack/Discord 等通信节点、数据库、AI、第三方 API 节点)。这样可以消化瞬时的 429 错误和短暂的上游故障,因此错误输出只会在真正发生故障时触发,告警和 5xx 响应也能反映实际问题,而非噪声。
{
retryOnFail: true,
maxTries: 3,
waitBetweenTries: 5000, // ms; 5000 is the max and should be your default
}
适用于所有调用网络服务的节点,不仅限于 HTTP Request。引擎会对任何错误进行重试,不按状态码筛选,并将 maxTries 上限设为 5、waitBetweenTries 上限设为 5000ms(packages/core/src/execution-engine/workflow-execute.ts)。节点特定说明请参阅 n8n-node-configuration-official 的 HTTP_NODES.md 和 AI_NODES.md。
响应格式:根据原因映射状态码
返回 text/plain "Internal Server Error" 的 5xx 响应在技术上属于 5xx,但毫无用处。而且并非所有错误都是 5xx。应根据请求失败的原因匹配状态码。
常见错误: 将所有错误路径都接到一个返回 500 "internal_error" 的 Respond to Webhook。即使调用方发送了错误输入,在调用方看来所有失败也都一样。这会破坏监控:你无法区分真正的服务中断和调用方输入错误。
按原因映射的默认值:
| 原因 | 状态码 | 错误代码 | 路径 |
|---|---|---|---|
| 缺少必填字段或类型错误 | 400 | validation_error | 使用基于 Set 的架构验证器提前验证(基本模式见 references/examples/validation-subworkflow.ts,端点模板见 validation-subworkflow-usage.ts);对于简单情况,也可以使用内联 IF/Switch + 专用的 400 响应。不要经过错误输出。理想情况下,在响应中回显架构,以便调用方自行修正。 |
| 缺少认证或认证无效 | 401 | unauthorized | 同上。提前检查,直接返回 401。 |
| 已通过认证,但无权访问 | 403 | forbidden | 同上。 |
| 请求中存在资源 ID,但数据中不存在 | 404 | not_found | 从查找结果分支,而不是从查找错误分支。 |
| 操作与当前状态冲突(重复、竞争) | 409 | conflict | 通过逻辑检测,而不是错误输出。 |
| 调用方超出速率限制 | 429 | rate_limit_exceeded | 设置 Retry-After 标头。 |
| 节点抛出异常,但原因未知 | 500 | internal_error | 错误输出路径。 |
| 第三方 API 出错 | 502 | upstream_error | HTTP Request 节点的错误输出。 |
| 工作流目前无法处理请求(下游服务宕机、上游服务触发速率限制) | 503 | service_unavailable | 根据具体错误检测,并附带提示返回。 |
| 第三方 API 超时 | 504 | upstream_timeout | 根据错误消息筛选错误输出。 |
两种不同的流程:
- **验证失败(4xx)**在执行工作之前通过 IF/Switch 分支检查,而不是通过错误输出处理。针对不同格式使用专用的 Respond(缺少字段时返回 400、未认证时返回 401,等等)。
- **执行失败(5xx)**来自错误输出(“我们尝试了,但出了问题”)。所有 5xx 共用一个错误响应节点即可。必要时,可检查失败的节点来区分响应正文中的
error代码。
使用一个 Respond,通过表达式设置状态码。 如果错误路径的差异仅在状态码和消息文本(正文格式相同,标头和内容类型没有变化),就不要通过 Switch 分流到 N 个 Respond 节点。Respond to Webhook 节点的 Response Code 和正文栏位支持表达式。直接内联计算状态码,让一个 Respond 节点处理整个错误路径。
// Response Code on a single Respond to Webhook node:
{{ (() => {
const msg = $json.error?.message || $json.message || ''
if (msg.includes('INVALID_ID')) return 400
if (/429|too many/i.test(msg)) return 429
if (/openrouter|anthropic|llm/i.test(msg)) return 502
return 500
})() }}
只有当响应在结构上存在差异时,Switch + N 个 Respond 节点才有必要:例如标头不同、正文格式不同、重定向或内容类型不同。格式相同、仅数字不同,就用一个由表达式驱动的 Respond。
完整约定(包括关联 ID、可重试与致命错误标志、验证详情和速率限制格式)请参阅 references/RESPONSE_SHAPES.md。
工作流级错误工作流
对于无人值守的工作流,请将实例的错误工作流(或单个工作流的覆盖设置)配置为指向一个工作流,该工作流需要:
- 捕获故障信息(工作流名称、执行 ID、错误、堆栈)。
- 通知相关人员(Slack、电子邮件、值班人员)。
- 可选地,将重试任务加入队列(使用退避策略)。
捕获逐节点处理无法处理的情况:超时、节点间崩溃、未接线节点中的错误。
请参阅 references/ERROR_WORKFLOWS.md。
参考文件
| 文件 | 阅读时机 |
|---|---|
references/API_WORKFLOWS.md | 构建或审查 webhook 触发/响应 webhook 工作流时 |
references/ERROR_WORKFLOWS.md | 为生产工作流设置工作流级错误捕获时 |
references/RESPONSE_SHAPES.md | 定义 API 的响应体规范时 |
references/NODE_ERROR_OUTPUTS.md | 为单个可能失败的节点连接按节点配置的错误输出时 |
反模式
| 反模式 | 问题 | 修复方法 |
|---|---|---|
| Webhook → 处理 → 响应,没有错误分支 | 调用方收到超时或空的 500 响应 | 将每个可能失败的节点的 output(1) 连接到 Respond to Webhook |
| 两条路径共用一个 Respond to Webhook | 响应体无法告知调用方发生了什么 | 使用两个 Respond 节点,每条路径各一个,并明确设置代码和响应体 |
错误路径返回 200,响应体为 { "error": ... } | 调用方的 HTTP 客户端会将其视为成功,因此不会触发错误处理 | 错误路径始终返回 4xx/5xx |
| 在 Code 节点中捕获错误,并将其作为数据返回 | 下游会收到错误格式的数据,工作流仍会继续 | 让它抛出错误,配置 onError: 'continueErrorOutput' 并连接错误路径 |
| 生产工作流没有工作流级错误工作流 | 真正发生故障时无处处理 | 设置错误工作流。参见 ERROR_WORKFLOWS.md |
| 每次失败都返回通用的“Internal Server Error” | 无法区分调用方错误、上游错误或速率限制 | 使用结构化错误代码。参见 RESPONSE_SHAPES.md |
生产节点调用不稳定或受速率限制的 API,却未设置 retryOnFail | 每次短暂的 429 或上游抖动都会表现为 5xx,并触发无谓的告警 | 在节点上设置 retryOnFail: true, maxTries: 3, waitBetweenTries: 5000。参见“短暂故障时的自愈” |
| 除 200 外的所有情况都返回 500 | 调用方无法区分自己的错误输入和服务中断,因此监控会因你的问题而触发告警 | 根据原因映射状态码。调用方问题使用 4xx。 |
| 根据错误消息使用 Switch → 多个仅状态码不同的 Respond 节点 | 5 个节点只为实现一个可由表达式驱动 Response Code 的 Respond | 在单个 Respond 中内联计算代码。参见上文“一个 Respond,由表达式驱动状态码”。 |