n8n-debugging-official
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesen8n Debugging
n8n 调试
When something breaks, the cause is almost always:
- Parameter misconfiguration (wrong value, wrong type, missing field).
- Stale assumptions (different version, different behavior than you remember).
- Paths misconfigured or misconnected (wrong output index, wrong merge input, missing wire, IF/Switch wired to the wrong branch).
- Upstream data stripped (an intermediate node replaced with its own output, so downstream
$jsonresolves to null even though "it should be there"). Fix: reference the stable upstream node by name ($json.x).$('Earlier Node').item.json.x - Item context lost (after Aggregate, Execute Once, or Split Out flows, n8n can't pair references deterministically, error reads like "The expression is referencing... multiple matching items"). Fix: Merge node to re-establish context,
.itemfor explicit lookup, or redesign to keep item correspondence stable (e.g., split into stateless sub-workflows).$input.all().find(...) - Logical errors (the wires are right and the parameters are right, but the workflow does the wrong thing, same as a logic bug in code).
- Genuine bug (rare but real).
Diagnose systematically: cheap checks first, deeper investigation only when those fail.
当工作流出现问题时,原因几乎总是以下情况之一:
- 参数配置错误(值错误、类型错误、字段缺失)。
- 过时假设(版本不同、行为与记忆中不符)。
- 路径配置或连接错误(输出索引错误、合并输入错误、连线缺失、IF/Switch连接到错误分支)。
- 上游数据被覆盖(中间节点用自身输出替换了,导致下游
$json解析为null,尽管“它应该存在”)。修复方法:通过节点名称引用稳定的上游节点($json.x)。$('Earlier Node').item.json.x - 项目上下文丢失(在聚合、单次执行或拆分流程后,n8n无法确定性地匹配引用,错误提示类似“表达式引用了……多个匹配项”)。修复方法:使用Merge节点重新建立上下文,使用
.item进行显式查找,或重新设计工作流以保持项目对应关系稳定(例如拆分为无状态子工作流)。$input.all().find(...) - 逻辑错误(连线和参数都正确,但工作流执行了错误的操作,与代码中的逻辑错误类似)。
- 真实bug(罕见但确实存在)。
系统地进行诊断:先进行简单检查,仅当这些检查失败时再进行深入调查。
Non-negotiable
不可协商原则
Believe the user. "This isn't working" means something isn't behaving as they expect, even if they describe the symptom imprecisely. Don't dismiss with "it should work" or "are you sure you're doing X?". Investigate first: the user is truth about what should happen, execution data and source are truth about what is happening. When you can't find the cause, "I don't know yet" beats a plausible-sounding fabrication.
相信用户。“无法正常工作”意味着某些行为不符合他们的预期,即使他们对症状的描述不够精确。不要用“它应该可以工作”或“你确定你做了X吗?”来敷衍。先进行调查:用户的描述是“应该发生的情况”的真实反馈,执行数据和源代码是“实际发生的情况”的真相。当你找不到原因时,“我目前还不清楚”比听起来合理的猜测要好。
Strong defaults (cause to cheap check)
优先检查项(按可能性排序)
Match cause to cheap check, in order of likelihood:
- Parameter misconfiguration → re-fetch via , compare against
get_node_types, look for type/value/missing-field mismatches.get_workflow_detailson the failing node alone returns per-parameter errors directly; faster than eyeballing the diff for nodes with deep / conditional shapes.validate_node_config
- Stale assumptions → ask the n8n version, ask when the user last updated the skills plugin, suspect drift if behavior contradicts the skill.
- Paths misconfigured or misconnected → inspect the object via
connections. For Merge input mismatches, seeget_workflow_detailsn8n-node-configuration-official.references/MERGE_NODE.md - Upstream data stripped → trace references back through the chain, look for any node that replaces the json with its own output. Common offenders: Aggregate, HTTP-binary, Extract from File, Code in "Run for All Items" mode, branching Merge. Not exhaustive: any node can do this if its output shape doesn't include the upstream fields.
$json.x - Item context lost → check downstream of any Aggregate / Execute Once / Split Out for references, switch to
.itemor a Merge anchor.$input.all().find(...) - Logical errors → trace data through step by step, compare each node's output vs. expected.
get_execution - Genuine bug → fall through to reading the n8n source, then GitHub issues, then a workaround.
For external API problems, the upstream service's API docs (not n8n's wrapper) are the truth. Fetch API docs and n8n's source code to debug if required.
将原因与简单检查项对应,按可能性从高到低排序:
- 参数配置错误 → 通过重新获取节点类型,与
get_node_types的结果对比,查找类型/值/缺失字段不匹配的情况。单独对故障节点运行get_workflow_details可直接返回每个参数的错误;对于具有深层/条件结构的节点,这比手动检查差异更快。validate_node_config
- 过时假设 → 询问用户的n8n版本,以及用户上次更新技能插件的时间,如果行为与技能描述不符,怀疑是版本漂移。
- 路径配置或连接错误 → 通过检查
get_workflow_details对象。对于合并输入不匹配的情况,请参阅connections的n8n-node-configuration-official。references/MERGE_NODE.md - 上游数据被覆盖 → 追踪引用的链路,查找任何用自身输出替换json的节点。常见的“罪魁祸首”包括:Aggregate、HTTP-binary、Extract from File、处于“为所有项目运行”模式的Code节点、分支Merge节点。但不限于这些:任何输出结构不包含上游字段的节点都可能导致这种情况。
$json.x - 项目上下文丢失 → 检查任何Aggregate / 单次执行 / 拆分流程后的下游引用,切换为
.item或使用Merge锚点。$input.all().find(...) - 逻辑错误 → 通过逐步追踪数据,比较每个节点的输出与预期结果。
get_execution - 真实bug → 最后查看n8n源代码,然后检查GitHub问题,再寻找解决方法。
对于外部API问题,上游服务的API文档(而非n8n的封装文档)是真相。必要时获取API文档和n8n源代码进行调试。
Step-by-step walkthrough
分步指南
When the cheap checks above don't immediately pinpoint the cause, work through these in order.
当上述简单检查无法立即确定原因时,按以下步骤操作:
Step 1: confirm the symptom
步骤1:确认症状
Ask:
- What did they expect?
- What actually happened?
- Error message text?
- When did it last work? What changed since?
Vague ("it's broken") becomes tractable when concrete ("email sends to wrong address" or "workflow returns 500 with empty body").
询问用户:
- 他们预期的结果是什么?
- 实际发生了什么?
- 错误消息的具体内容是什么?
- 它上次正常工作是什么时候?从那以后发生了什么变化?
模糊的描述(“它坏了”)会在具体化后变得易于处理(“邮件发送到了错误的地址”或“工作流返回500错误且响应体为空”)。
Step 2: check the execution
步骤2:检查执行记录
get_execution({ executionId: <execution_id>, workflowId: <workflow_id>, includeData: true })Look at:
- Which node failed?
- What input did it have?
- What error message? Read carefully. Usually points at the cause.
No execution ID? Ask the user to re-run.
get_execution({ executionId: <execution_id>, workflowId: <workflow_id>, includeData: true })查看以下内容:
- 哪个节点失败了?
- 它的输入是什么?
- **错误消息是什么?**仔细阅读,通常会指向原因。
没有执行ID?请用户重新运行工作流。
Step 3: re-fetch the workflow
步骤3:重新获取工作流详情
get_workflow_details({ workflowId: <workflow_id> })Confirm the actual current state. The user might be looking at a different workflow or remembering a stale version.
Compare:
- Nodes vs. the user's mental model.
- Connections vs. intent: pull via and compare the
get_workflow_detailsobject to the SDK code.connections - Credentials vs. expected (per ).
n8n-credentials-and-security-official - Upstream-strip risk: any node between a data source and a downstream consumer that replaces the json with its own output? Common offenders are HTTP-binary, Extract from File, Aggregate, Code in "Run for All Items" mode, and branching Merge, but any node can do this if its output shape doesn't include the upstream fields. The consumer should reference the source node by name (
$json.x), not$('Source Node').item.json.x. Otherwise the field silently resolves to null.$json - Item-context risk: any Aggregate / Execute Once / Split Out followed by downstream references? n8n may not be able to pair items deterministically. Look for "The expression is referencing... multiple matching items" in past executions.
.item
get_workflow_details({ workflowId: <workflow_id> })确认工作流的实际当前状态。用户可能正在查看不同的工作流,或者记忆中的版本已过时。
对比:
- 节点与用户的心理模型是否一致。
- 连接与预期是否一致:通过获取
get_workflow_details对象,并与SDK代码对比。connections - 凭据是否符合预期(参考)。
n8n-credentials-and-security-official - 上游数据覆盖风险:在数据源和下游消费者之间,是否有任何节点用自身输出替换了json?常见的包括HTTP-binary、Extract from File、Aggregate、处于“为所有项目运行”模式的Code节点和分支Merge节点,但任何输出结构不包含上游字段的节点都可能导致这种情况。消费者应该通过节点名称引用源节点(
$json.x),而不是使用$('Source Node').item.json.x。否则该字段会静默解析为null。$json - 项目上下文丢失风险:是否有任何Aggregate / 单次执行 / 拆分流程后跟随下游引用?n8n可能无法确定性地匹配项目。查看过去的执行记录中是否有“表达式引用了……多个匹配项”的错误。
.item
Step 4: re-fetch the node types
步骤4:重新获取节点类型
get_node_types([{ name: '<failed-node>', resource: '...', operation: '...' }])Compare actual parameter shape vs. configured. Common mismatches:
- Missing required parameter.
- Wrong type (string vs. number, etc.).
- and
objectare distinct in n8n's UI type dropdowns (Set, IF, Switch, Filter, anywhere the UI asks you to pick a type). Pickingarraywon't accept an array value, and vice versa. Inside expressions themselves it's normal JS (arrays are objects), so the distinction only bites at those UI type-pick surfaces. Watch for this when aobjectexpression returns the wrong container shape for a typed slot.={{ ... }} - A dependent parameter set without its parent (e.g., without
credentials, orauthentication !== 'none'withoutquery). Re-fetch withoperation === 'executeQuery'passing the right discriminators.get_node_types
If the manual shape-vs-config diff is tedious (deep params, AI tool subnodes, many conditional branches), run directly. Returns per failure. For tool subnodes set .
validate_node_config{ path, message }isToolNode: trueget_node_types([{ name: '<failed-node>', resource: '...', operation: '...' }])对比实际参数结构与配置的参数结构。常见的不匹配情况:
- 缺少必填参数。
- 类型错误(字符串 vs 数字等)。
- n8n的UI类型下拉菜单中,和
object是不同的类型(Set、IF、Switch、Filter等任何UI要求选择类型的地方)。选择array不会接受数组值,反之亦然。在表达式内部是标准JS(数组也是对象),因此这种区别仅在UI类型选择界面生效。当object表达式返回的容器类型与类型插槽不匹配时,要注意这种情况。={{ ... }} - 设置了依赖参数但未设置其父参数(例如,时设置
authentication !== 'none',或credentials时设置operation === 'executeQuery')。传递正确的鉴别器重新运行query。get_node_types
如果手动对比结构与配置的差异很繁琐(深层参数、AI工具子节点、多个条件分支),直接运行。它会返回每个失败项的。对于工具子节点,设置。
validate_node_config{ path, message }isToolNode: trueStep 5: test with pinned data
步骤5:使用固定数据测试
prepare_test_pin_data({ workflowId: '<id>' })
test_workflow({ workflowId: '<id>' })Controlled input isolates "workflow broken?" from "input weird?". If pinned data works but real input fails, the issue is in real input handling.
If pinned data also produces wrong output, that's likely a logical error: trace each node's output against what you expected. on the test run gives you the actual emitted data per step, which is the source of truth for what each node did.
get_executionprepare_test_pin_data({ workflowId: '<id>' })
test_workflow({ workflowId: '<id>' })受控输入可以区分“工作流损坏?”和“输入异常?”。如果固定数据可以正常运行但真实输入失败,问题出在真实输入的处理上。
如果固定数据也产生错误输出,那很可能是逻辑错误:逐步追踪每个节点的输出与预期结果。测试运行的会提供每个步骤的实际输出数据,这是每个节点执行情况的真相。
get_executionStep 6: read the n8n source
步骤6:查看n8n源代码
When everything checks out and behavior still seems wrong:
github.com/n8n-io/n8n- for built-in nodes.
packages/nodes-base/nodes/<NodeName> - for execution logic.
packages/cli/src/... - for workflow runtime.
packages/core/src/...
The behavior of the code is truth.
See .
references/FETCHING_N8N_SOURCE.md当所有检查都通过但行为仍然异常时:
github.com/n8n-io/n8n- 内置节点位于。
packages/nodes-base/nodes/<NodeName> - 执行逻辑位于。
packages/cli/src/... - 工作流运行时位于。
packages/core/src/...
代码的行为就是真相。
请参阅。
references/FETCHING_N8N_SOURCE.mdStep 7: suspect drift on either side
步骤7:怀疑双方版本漂移
If steps 1-6 all check out and behavior still doesn't match expectations, version drift is the most likely remaining cause. Two sides drift independently:
<!-- TEMPORARY: when instance metadata tool is added, change asking user to just using the tool -->
- Their n8n instance version. Ask. (UI: , or
Settings → About.) On older instances, parameters and tools the skill assumes may be missing; on very new ones, parameter shapes or tool names may have moved. Suggest updating to the latest n8n release, or if a fix is rumored or the issue is recent, the latest beta.GET /rest/settings - This skill plugin's version. These skills drift relative to n8n over time. If the user installed the plugin a while ago, suggest (or the plugin manager's update command) on the skills repo. See the README's "Drift" section.
git pull
Drift surfaces as: parameter shape mismatches in , MCP tools that don't exist or carry new parameters, tool descriptions that contradict what the skill teaches, behavior diverging from the skill's claims. When you spot any of those, surface drift explicitly to the user: "This may be drift between your n8n version and these skills. Can you tell me your n8n version, and when you last updated the skills?"
get_node_typesIf after updating both sides the issue persists, proceed to Step 8.
如果步骤1-6都检查通过但行为仍然不符合预期,版本漂移是最可能的剩余原因。双方可能独立发生漂移:
<!-- TEMPORARY: 当添加实例元数据工具后,将询问用户改为直接使用该工具 -->
- 用户的n8n实例版本。询问用户。(UI路径:,或调用
Settings → About接口。)在旧版本实例中,技能假设存在的参数和工具可能缺失;在非常新的版本中,参数结构或工具名称可能已更改。建议用户更新到最新的n8n版本,如果有传闻中的修复或问题是最近出现的,建议更新到最新的beta版本。GET /rest/settings - 此技能插件的版本。这些技能会随着时间推移与n8n产生漂移。如果用户安装插件已有一段时间,建议用户在技能仓库执行(或插件管理器的更新命令)。请参阅README中的“漂移”部分。
git pull
漂移的表现包括:中的参数结构不匹配、不存在的MCP工具或带有新参数的工具、工具描述与技能教学内容矛盾、行为与技能声明不符。当你发现任何这些情况时,明确向用户指出漂移:“这可能是你的n8n版本与这些技能之间的版本漂移。你能告诉我你的n8n版本,以及你上次更新技能的时间吗?”
get_node_types如果更新双方版本后问题仍然存在,继续步骤8。
Step 8: report or workaround
步骤8:报告问题或寻找解决方法
For confirmed bugs:
- Have the user post a question on https://community.n8n.io
- Surface a clear repro to the user.
- Check n8n GitHub issues. May already be filed.
- If blocking, work around (different node/approach) and note in workflow notes.
- If a fix is in progress, mark workarounds with
<!-- TEMPORARY: ... -->
对于已确认的bug:
- 让用户在https://community.n8n.io上发布问题。
- 向用户提供清晰的复现步骤。
- 检查n8n的GitHub问题,可能已经有人提交过。
- 如果问题阻塞了工作,寻找替代方案(不同节点/方法)并在工作流备注中记录。
- 如果修复正在进行中,用标记解决方法。
<!-- TEMPORARY: ... -->
Reference files
参考文件
| File | Read when |
|---|---|
| Parameters might be misconfigured, need a systematic re-check |
| n8n behavior contradicts docs, need to read the actual code |
| 文件 | 阅读场景 |
|---|---|
| 参数可能配置错误,需要系统地重新检查 |
| n8n行为与文档矛盾,需要查看实际代码 |
Anti-patterns
反模式
| Anti-pattern | What goes wrong | Fix |
|---|---|---|
| "It should work, are you sure you're doing X?" | Dismisses the user's report, misses real issues | Believe the user. Investigate. |
| Re-running without checking the execution | Same failure twice, no new info | |
| Assuming docs are accurate when behavior contradicts | Accepting the wrong mental model | Read the source. Behavior is truth |
| Re-implementing logic in a Code node when a configured node fails | Hides the bug, doesn't fix root cause | Diagnose first, only work around when the bug is confirmed |
| Bisecting by deleting nodes randomly | Wastes time | Step through |
| Asking the user to re-screenshot instead of inspecting via MCP | Slow, error-prone | Use |
| Calling it "fixed" when you've worked around the bug, not understood it | Bug recurs in slightly different form | Document the cause. If working around, mark with |
| Declaring a "bug" without asking the user's n8n version or when they last updated the skills | Real cause is often drift, and user updates and the "bug" disappears | Ask both versions before reporting. See Step 7. |
| 反模式 | 问题所在 | 修复方法 |
|---|---|---|
| “它应该可以工作,你确定你做了X吗?” | 否定用户的反馈,忽略真实问题 | 相信用户。进行调查。 |
| 不检查执行记录就重新运行 | 重复相同的失败,无法获取新信息 | 对失败的运行调用 |
| 当行为与文档矛盾时假设文档准确 | 接受错误的心理模型 | 查看源代码。行为就是真相 |
| 当配置好的节点失败时在Code节点中重新实现逻辑 | 隐藏bug,不解决根本原因 | 先诊断,仅当确认是bug时再寻找解决方法 |
| 通过随机删除节点进行二分排查 | 浪费时间 | 通过 |
| 要求用户重新截图而不是通过MCP检查 | 缓慢且容易出错 | 使用 |
| 当你只是找到解决方法而不是理解原因时就宣称“已修复” | bug会在稍有不同的场景中复发 | 记录原因。如果使用解决方法,用 |
| 在询问用户的n8n版本或上次更新技能的时间之前就宣称是“bug” | 真正的原因通常是版本漂移,用户更新后“bug”会消失 | 报告前询问两个版本。请参阅步骤7。 |