n8n-io/n8n · error · Error

Named object syntax does not support .onEachBatch() - branch

Error message

Named object syntax does not support .onEachBatch() - branches are configured in the constructor

What it means

Thrown by NamedSplitInBatchesBuilderImpl.onEachBatch(). The named-object form of splitInBatches() fixes the each and done branches at construction time (via the branches object), so the fluent .onEachBatch() method — which appends to the each branch after construction — is not supported on this builder variant.

Source

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

		if (branches.each !== null) {
			const firstEachNodes = getFirstNodes(branches.each);
			if (firstEachNodes.length > 1) {
				this._eachBatches.push(firstEachNodes);
			} else if (firstEachNodes.length === 1) {
				this._eachBatches.push(firstEachNodes[0]);
			}
			// For named syntax, we DON'T set _hasLoop because the loop is already
			// expressed in the connection target (e.g., each: sibNode or each: processNode.to(sibNode))
			// The workflow-builder's _hasLoop handling is only for the fluent API's .loop() method
		}
	}

	/**
	 * Fluent API: Not supported for named syntax builder (use constructor branches instead)
	 */
	onEachBatch(_target: BranchTarget): this {
		throw new Error(
			'Named object syntax does not support .onEachBatch() - branches are configured in the constructor',
		);
	}

	/**
	 * Fluent API: Not supported for named syntax builder (use constructor branches instead)
	 */
	onDone(_target: BranchTarget): this {
		throw new Error(
			'Named object syntax does not support .onDone() - branches are configured in the constructor',
		);
	}

	getAllNodes(): Array<NodeInstance<string, string, unknown>> {
		return [this.sibNode, ...this._doneNodes, ...this._eachNodes];
	}

	getDoneNodes(): Array<NodeInstance<string, string, unknown>> {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Provide the each branch in the constructor object: splitInBatches('sib', { each: handler, done: endNode }).
  2. If you need .onEachBatch(), switch to the fluent builder variant that supports it.
  3. Do not mix named-object construction with fluent branch methods.

Example fix

// before
const sib = splitInBatches('sib', { done: endNode });
sib.onEachBatch(processNode); // throws
// after
const sib = splitInBatches('sib', { each: processNode, done: endNode });
Defensive patterns

Strategy: type-guard

Validate before calling

function isNamedSyntaxBuilder(b: unknown): boolean {
  return b instanceof NamedSplitInBatchesBuilderImpl;
}

if (isNamedSyntaxBuilder(builder)) {
  throw new Error('Use constructor branches { each, done }, not .onEachBatch()');
}

Type guard

function supportsFluentBranches(b: SplitInBatchesBuilder): boolean {
  // named-syntax builders throw on .onEachBatch(); fluent builders do not
  return !Object.is(b.onEachBatch, NamedSplitInBatchesBuilderImpl.prototype.onEachBatch);
}

Try / catch

try {
  builder.onEachBatch(target);
} catch (e) {
  if (e instanceof Error && /Named object syntax does not support/.test(e.message)) {
    // reconfigure via constructor branches instead
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing a SplitInBatches builder with the named-object syntax `splitInBatches('sib', { each, done })` and then calling .onEachBatch(target) on the returned builder.

Common situations: Developer starts with named syntax then tries to append fluent calls; refactoring between named and fluent styles halfway through; copy-paste from a fluent-style example onto a named-syntax builder.

Related errors


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