n8n-io/n8n · error · Error

SplitInBatches node output connections are managed by SplitI

Error message

SplitInBatches node output connections are managed by SplitInBatchesBuilder

What it means

Thrown by SplitInBatchesNodeInstance.output(). The SplitInBatches node's output ports (each / done) are owned by SplitInBatchesBuilder, which is the only place that can correctly declare which output index a downstream node binds to. Calling .output() on the raw node is blocked for the same ownership reason as .input().

Source

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

	update(
		config: Partial<NodeConfig>,
	): NodeInstance<'n8n-nodes-base.splitInBatches', string, unknown> {
		return new SplitInBatchesNodeInstance({
			version: this.version,
			config: {
				...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 [];
	}
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Configure output targets through the builder's each/done branches.
  2. Use the fluent builder's .onEachBatch() / .onDone() (fluent variant) to bind output targets.
  3. Do not call .output() on a SplitInBatches node.

Example fix

// before
sibNode.output(0).to(processNode);
// after
splitInBatches('sib', { each: processNode, done: endNode });
Defensive patterns

Strategy: type-guard

Validate before calling

function safeOutput(node: NodeInstance, i: number): OutputSelector<any, any, any> {
  if (node.type === 'n8n-nodes-base.splitInBatches') {
    throw new Error('Use SplitInBatchesBuilder each/done branches instead of .output()');
  }
  return node.output(i);
}

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.output(0) or sibNode.output(1) directly to get an OutputSelector; generic code that fans out via .output(i) for every multi-output node.

Common situations: Treating SplitInBatches like a generic multi-output node; constructing a manual connection from a specific SIB output index.

Related errors


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