{"record":{"id":"965364975c59dffa","repo":"n8n-io/n8n","slug":"node-edge-to-has-more-than-one-edge-into-input","errorCode":null,"errorMessage":"Node ${edge.to} has more than one edge into input slot ${edge.inputIndex}; converging branches on one slot is not supported yet","messagePattern":"Node (.+?) has more than one edge into input slot (.+?); converging branches on one slot is not supported yet","errorType":"exception","errorClass":"UnimplementedError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/engine/src/graph/validate-executable-graph.ts","lineNumber":70,"sourceCode":"\t}\n\n\t// TODO(CAT-2874): multi-slot outputs arrive with branching; until then only\n\t// output slot 0 fires, and the runtime can assume single-slot outputs.\n\tfor (const edge of graph.edges) {\n\t\tif (edge.outputIndex !== 0) {\n\t\t\tthrow new UnimplementedError(\n\t\t\t\t`Edge ${edge.from} → ${edge.to} leaves output slot ${edge.outputIndex}; only output slot 0 is supported yet`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// TODO(CAT-3982): same-slot convergence gets a defined meaning (concatenation);\n\t// until then it is rejected rather than given accidental semantics.\n\tconst seenInputSlots = new Set<string>();\n\tfor (const edge of graph.edges) {\n\t\tconst slot = `${edge.to}#${edge.inputIndex}`;\n\t\tif (seenInputSlots.has(slot)) {\n\t\t\tthrow new UnimplementedError(\n\t\t\t\t`Node ${edge.to} has more than one edge into input slot ${edge.inputIndex}; converging branches on one slot is not supported yet`,\n\t\t\t);\n\t\t}\n\t\tseenInputSlots.add(slot);\n\t}\n}\n","sourceCodeStart":52,"sourceCodeEnd":77,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/engine/src/graph/validate-executable-graph.ts#L52-L77","documentation":"Thrown by validateExecutableGraph() as an UnimplementedError when two or more edges feed the same input slot of one node (same `${to}#${inputIndex}` seen twice). The engine does not yet define convergence semantics for a single input slot (planned under CAT-3982 as concatenation), so it rejects the shape rather than silently picking one input. Over HTTP this becomes 501 {error:'unimplemented', reason:...}. The graph is valid in principle but uses an unsupported topology.","triggerScenarios":"POST /workflow-executions with a graph where two distinct source nodes both connect into the same target node's inputIndex 0 (e.g. edges {from:'A',to:'M',inputIndex:0} and {from:'B',to:'M',inputIndex:0}). Common when translating a v1 Merge node or a fan-in pattern where branches reconverge.","commonSituations":"Porting a v1 workflow that uses a Merge node (multiple inputs converge). Building a fan-in/fan-out pattern in the new engine before CAT-3982 lands. Two trigger-adjacent paths that rejoin at a single node input.","solutions":["Give the converging edges different inputIndex values on the target node (e.g. route branch A into inputIndex 0 and branch B into inputIndex 1) so no slot is hit twice.","Insert an intermediary node that serializes the branches so only one edge enters each slot.","Wait for CAT-3982 (same-slot convergence as concatenation) before porting fan-in workflows.","Pre-validate client-side: build a Set of `${to}#${inputIndex}` and reject duplicates before submitting."],"exampleFix":"// before — two edges into the same input slot 0 of 'merge'\nedges: [\n  { from: 'branchA', to: 'merge', inputIndex: 0 },\n  { from: 'branchB', to: 'merge', inputIndex: 0 }\n]\n// after — split across distinct input slots\nedges: [\n  { from: 'branchA', to: 'merge', inputIndex: 0 },\n  { from: 'branchB', to: 'merge', inputIndex: 1 }\n]","handlingStrategy":"validation","validationCode":"function assertNoInputSlotConvergence(graph) {\n  const seen = new Set();\n  for (const e of graph.edges) {\n    const slot = `${e.to}#${e.inputIndex ?? 0}`;\n    if (seen.has(slot)) throw new Error(`Convergence on ${slot}`);\n    seen.add(slot);\n  }\n}","typeGuard":"function hasNoInputConvergence(graph) {\n  const seen = new Set();\n  for (const e of graph.edges) {\n    const slot = `${e.to}#${e.inputIndex ?? 0}`;\n    if (seen.has(slot)) return false;\n    seen.add(slot);\n  }\n  return true;\n}","tryCatchPattern":"const res = await fetch('/workflow-executions', { method: 'POST', body: JSON.stringify(payload) });\nif (res.status === 501) {\n  const body = await res.json();\n  if (body.error === 'unimplemented' && body.reason.includes('converging branches')) {\n    // reassign one edge to a different inputIndex and resubmit\n  }\n}","preventionTips":["Give each incoming edge of a target node a distinct inputIndex.","Build a Set of `${to}#${inputIndex}` locally before submitting.","Insert an intermediary node to serialize converging branches until CAT-3982 lands."],"tags":["engine","graph-validation","unimplemented","convergence"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}