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
- Model a single synthetic root and make all other top-level nodes children of it.
- Switch the tree strategy to closure-table or materialized-path (`tree.type: 'closure-table'` / `'materialized-path'`), which support multiple roots.
- 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
- Pick nested-set only when you need exactly one root; otherwise use closure-table or materialized-path.
- Create a single synthetic root at seed time and forbid parent-less inserts thereafter.
- Guard insert paths with a roots-exist check before saving a parent-less node.
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
- Cannot attach entity "${entityName}" to its parent. Please m
- Tree repositories are not supported in ${driver.options.type
- Cannot ${operation}, given value must be instance of entity
- Removed entity "${subject.metadata.name}" is also scheduled
- Internal error. Subject ${subject.metadata.targetName} must
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/9ded6b99bef24f28.
Report an issue: GitHub.