n8n-io/n8n · error · NestedSetMultipleRootError

Nested sets do not support multiple root entities.

Error message

Nested sets do not support multiple root entities.

What it means

Nested-set trees model hierarchy with left/right bounds and, by design, support exactly ONE root entity per tree. When inserting a node whose parent is null/undefined (i.e. a candidate root), `NestedSetSubjectExecutor` calls `isUniqueRootEntity`; if a root already exists in the table, it throws `NestedSetMultipleRootError`.

Source

Thrown at packages/@n8n/typeorm/src/persistence/tree/NestedSetSubjectExecutor.ts:79

		if (parentNsRight !== undefined) {
			await this.queryRunner.query(
				`UPDATE ${tableName} SET ` +
					`${leftColumnName} = CASE WHEN ${leftColumnName} > ${parentNsRight} THEN ${leftColumnName} + 2 ELSE ${leftColumnName} END,` +
					`${rightColumnName} = ${rightColumnName} + 2 ` +
					`WHERE ${rightColumnName} >= ${parentNsRight}`,
			);

			OrmUtils.mergeDeep(
				subject.insertedValueSet,
				subject.metadata.nestedSetLeftColumn!.createValueMap(parentNsRight),
				subject.metadata.nestedSetRightColumn!.createValueMap(parentNsRight + 1),
			);
		} else {
			const isUniqueRoot = await this.isUniqueRootEntity(subject, parent);

			// Validate if a root entity already exits and throw an exception
			if (!isUniqueRoot) throw new NestedSetMultipleRootError();

			OrmUtils.mergeDeep(
				subject.insertedValueSet,
				subject.metadata.nestedSetLeftColumn!.createValueMap(1),
				subject.metadata.nestedSetRightColumn!.createValueMap(2),
			);
		}
	}

	/**
	 * Executes operations when subject is being updated.
	 */
	async update(subject: Subject): Promise<void> {
		let parent = subject.metadata.treeParentRelation!.getEntityValue(subject.entity!); // if entity was attached via parent
		if (!parent && subject.parentSubject && subject.parentSubject.entity)
			// if entity was attached via children
			parent = subject.parentSubject.entity;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Model a single synthetic root and make all other top-level nodes children of it.
  2. Switch the tree strategy to closure-table or materialized-path (`tree.type: 'closure-table'` / `'materialized-path'`), which support multiple roots.
  3. Query for an existing root before inserting; if present, attach the new node as its child instead.

Example fix

// before — second root in a nested-set tree
const root2 = new Category(); root2.name = 'root2';
await treeRepo.save(root2); // a root already exists → NestedSetMultipleRootError

// after — attach under the existing root
const existingRoot = await treeRepo.findRoots();
root2.parent = existingRoot[0];
await treeRepo.save(root2);
Defensive patterns

Strategy: validation

Validate before calling

// Before saving a potential nested-set root, check no root exists
if (!node.parent) {
  const roots = await treeRepo.findRoots();
  if (roots.length > 0) {
    throw new Error('Nested-set tree already has a root; attach this node under it or switch tree type.');
  }
}

Try / catch

try { await treeRepo.save(node); } catch (e) { if (e instanceof NestedSetMultipleRootError) { /* attach under existing root or switch tree type */ } throw e; }

Prevention

When it happens

Trigger: Inserting a second root into a nested-set tree: saving a node with no parent after a root already exists. Bulk-inserting multiple parent-less nodes.

Common situations: Choosing the nested-set tree type for data that needs multiple roots (e.g. multiple independent category trees). Seeding the DB and inserting two top-level categories. Migrating from another tree type without consolidating under a single root.

Related errors


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