n8n-io/n8n · error · Error

SplitInBatches node connections are managed by SplitInBatche

Error message

SplitInBatches node connections are managed by SplitInBatchesBuilder

What it means

Thrown by SplitInBatchesNodeInstance.to(). The .to() method is the standard fan-out wiring entry point on NodeInstance, but SplitInBatches loop wiring must be declared through SplitInBatchesBuilder so that the loop-back edge is generated correctly. Calling .to() directly is rejected to prevent half-declared loops.

Source

Thrown at packages/@n8n/workflow-sdk/src/workflow-builder/control-flow-builders/split-in-batches.ts:67

				...this.config,
				...config,
			},
		});
	}

	input(_index: number): InputTarget {
		throw new Error('SplitInBatches node input connections are managed by SplitInBatchesBuilder');
	}

	output(_index: number): OutputSelector<'n8n-nodes-base.splitInBatches', string, unknown> {
		throw new Error('SplitInBatches node output connections are managed by SplitInBatchesBuilder');
	}

	to<T extends NodeInstance<string, string, unknown>>(
		_target: T | T[] | InputTarget,
		_outputIndex?: number,
	): NodeChain<NodeInstance<'n8n-nodes-base.splitInBatches', string, unknown>, T> {
		throw new Error('SplitInBatches node connections are managed by SplitInBatchesBuilder');
	}

	onError<T extends NodeInstance<string, string, unknown>>(_handler: T): this {
		throw new Error('SplitInBatches node error handling is managed by SplitInBatchesBuilder');
	}

	getConnections(): DeclaredConnection[] {
		return [];
	}
}

/**
 * A batch of nodes - either a single node or an array of nodes for fan-out
 */
export type NodeBatch =
	| NodeInstance<string, string, unknown>
	| Array<NodeInstance<string, string, unknown>>;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Declare each/done branches in the splitInBatches() factory or via the fluent builder's .onEachBatch()/.onDone().
  2. Route into the SIB through the builder rather than calling .to() on the node.
  3. Use the builder's getAllNodes()/getConnections() to obtain declared edges.

Example fix

// before
source.to(sibNode).to(processNode);
// after
const sib = splitInBatches('sib', { each: processNode, done: endNode });
workflow(source, sib);
Defensive patterns

Strategy: type-guard

Validate before calling

function safeTo<T extends NodeInstance<any, any, any>>(src: NodeInstance, target: T): NodeChain<any, T> {
  if (src.type === 'n8n-nodes-base.splitInBatches') {
    throw new Error('SplitInBatches .to() is managed by the builder');
  }
  return src.to(target);
}

Type guard

function isSplitInBatches(node: NodeInstance): node is NodeInstance<'n8n-nodes-base.splitInBatches', string, unknown> {
  return node.type === 'n8n-nodes-base.splitInBatches';
}

Prevention

When it happens

Trigger: Calling sibNode.to(target) or sibNode.to([a, b]); fluent code that chains source.to(sib).to(after) without going through the builder.

Common situations: Placing a SplitInBatches node mid-chain via .to(); assuming the standard .to() semantics apply to loop nodes.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/92e64009b89972d3. Report an issue: GitHub.