n8n-io/n8n · error · Error

Named object syntax does not support .onDone() - branches…

Error message

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

What it means

Thrown by NamedSplitInBatchesBuilderImpl.onDone(). Symmetric to onEachBatch: the named-object builder variant fixes the done branch in the constructor and does not accept the fluent .onDone() method, which would mutate the done target after construction.

Solutions

  1. Provide the done branch in the constructor object: splitInBatches('sib', { each, done: endNode }).
  2. Switch to the fluent builder variant if you need .onDone().
  3. Decide on one style (named vs fluent) per SplitInBatches and stay with it.

Example fix

// before
const sib = splitInBatches('sib', { each: processNode });
sib.onDone(endNode); // 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 .onDone()');
}

Type guard

function supportsFluentBranches(b: SplitInBatchesBuilder): boolean {
  return !Object.is(b.onDone, NamedSplitInBatchesBuilderImpl.prototype.onDone);
}

Try / catch

try {
  builder.onDone(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 with named syntax and then calling .onDone(target) on the returned builder.

Common situations: Mixing styles; refactoring a fluent-style chain onto a named-syntax builder; appending a done handler after the fact.

Related errors


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

Appendix: source

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

			// 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>> {
		return this._doneNodes;
	}

	getEachNodes(): Array<NodeInstance<string, string, unknown>> {
		return this._eachNodes;
	}

	hasLoop(): boolean {
		return this._hasLoop;

View on GitHub (pinned to 5ac6606e81)