n8n-io/n8n · error · ConnectionError
INVALID_CONNECTION
INVALID_CONNECTION
Error message
Invalid connection
What it means
Thrown by the connect_nodes tool after validateConnection() (utils/connection.utils) returns { valid: false }. The tool already inferred a connection type and applied its swap heuristic, but the final source/target/type topology is still not permitted by the node types' declared inputs and outputs. validation.error carries the specific reason when available, otherwise the generic 'Invalid connection' fallback is used.
Source
Thrown at packages/@n8n/ai-workflow-builder.ee/src/tools/connect-nodes.tool.ts:214
`Connecting ${matchedSourceNode.name} to ${matchedTargetNode.name}...`,
);
// Validate connection and check if nodes need to be swapped
const validation = validateConnection(
matchedSourceNode,
matchedTargetNode,
connectionType,
nodeTypes,
);
if (!validation.valid) {
const connectionError = new ConnectionError(validation.error ?? 'Invalid connection', {
fromNodeId: matchedSourceNode.id,
toNodeId: matchedTargetNode.id,
});
const error = {
message: connectionError.message,
code: 'INVALID_CONNECTION',
details: {
sourceNode: matchedSourceNode.name,
targetNode: matchedTargetNode.name,
connectionType,
},
};
reporter.error(error);
return createErrorResponse(config, error);
}
// Use potentially swapped nodes
const actualSourceNode = validation.swappedSource ?? matchedSourceNode;
const actualTargetNode = validation.swappedTarget ?? matchedTargetNode;
// Track if nodes were swapped either during inference or validation
const swapped = inferredSwap || !!validation.shouldSwap;
// Create only the new connection (not the full connections object)
// This is important for parallel execution - each tool only returns its own connectionView on GitHub (pinned to 5ac6606e81)
Solutions
- Inspect details.connectionType and details.sourceNode/targetNode, then check each node type's inputs/outputs to find a genuinely compatible pair.
- Try the inverse direction explicitly (swap sourceNodeId and targetNodeId) in case inference picked the wrong orientation.
- Insert a bridging node (No-Op, Set, or Merge) whose inputs/outputs match both ends.
Example fix
// before: two triggers cannot connect
await connect_nodes.invoke({ sourceNodeId: triggerA, targetNodeId: triggerB });
// after: route through a Set node that accepts main input and emits main output
await connect_nodes.invoke({ sourceNodeId: triggerA, targetNodeId: setNode });
await connect_nodes.invoke({ sourceNodeId: setNode, targetNodeId: triggerB }); Defensive patterns
Strategy: validation
Validate before calling
// Before calling connect_nodes, confirm the two node types share a compatible
// connection type by inspecting their INodeTypeDescription outputs/inputs.
function findCompatibleConnectionType(src: INodeTypeDescription, tgt: INodeTypeDescription): string | null {
const outTypes = new Set((src.outputs.main?.[0] ?? []).flatMap((o) => o));
for (const input of tgt.inputs.main ?? []) {
if (input.some((t) => outTypes.has(t))) return 'main';
}
// repeat for ai_* keys present on both sides
return null;
}
const type = findCompatibleConnectionType(srcType, tgtType);
if (!type) { /* surface guidance to caller instead of invoking */ } Type guard
function isToolError(v: unknown): v is { message: string; code: string; details?: unknown } {
return typeof v === 'object' && v !== null && 'code' in v && 'message' in v;
} Try / catch
// connect_nodes returns a structured error response rather than throwing, so
// inspect the returned object's code field rather than try/catch.
const res = await connect_nodes.invoke(input);
if (isToolError(res) && res.code === 'INVALID_CONNECTION') {
// read res.details.connectionType / sourceNode / targetNode, pick a different pair
} Prevention
- Maintain a registry of node type IO signatures and pre-validate pairs before invoking connect_nodes.
- Prefer connecting through well-known bridge nodes (No-Op, Set) when type compatibility is uncertain.
- Log the inferred connectionType on success to build a compatibility map over time.
When it happens
Trigger: Calling connect_nodes with two node IDs whose node types share no compatible output/input pair after type inference and swap; e.g. two trigger nodes, or two main nodes where a sub-node/main-node relationship is required.
Common situations: Trying to chain two trigger nodes (both only produce, neither consumes main); connecting a node whose only output type is ai_memory to a target with no ai_memory input; connecting nodes whose versions changed their IO declarations.
Related errors
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/2f9f79d71956a0bd.
Report an issue: GitHub.