{"record":{"id":"212d6052939f2d25","repo":"n8n-io/n8n","slug":"cannot-attach-entity-entityname-to-its-parent","errorCode":null,"errorMessage":"Cannot attach entity \"${entityName}\" to its parent. Please make sure parent is saved in the database before saving children nodes.","messagePattern":"Cannot attach entity \"(.+?)\" to its parent\\. Please make sure parent is saved in the database before saving children nodes\\.","errorType":"exception","errorClass":"CannotAttachTreeChildrenEntityError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/typeorm/src/persistence/tree/ClosureSubjectExecutor.ts","lineNumber":85,"sourceCode":"\t\t\t);\n\t\t\tconst childEntityIds1 = subject.metadata.primaryColumns.map((column) => {\n\t\t\t\tqueryParams.push(\n\t\t\t\t\tcolumn.getEntityValue(\n\t\t\t\t\t\tsubject.insertedValueSet ? subject.insertedValueSet : subject.entity!,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\treturn this.queryRunner.connection.driver.createParameter(\n\t\t\t\t\t'child_entity_' + column.databaseName,\n\t\t\t\t\tqueryParams.length - 1,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tconst whereCondition = subject.metadata.closureJunctionTable.descendantColumns.map(\n\t\t\t\t(column) => {\n\t\t\t\t\tconst columnName = escape(column.databaseName);\n\t\t\t\t\tconst parentId = column.referencedColumn!.getEntityValue(parent);\n\n\t\t\t\t\tif (!parentId) throw new CannotAttachTreeChildrenEntityError(subject.metadata.name);\n\n\t\t\t\t\tqueryParams.push(parentId);\n\t\t\t\t\tconst parameterName = this.queryRunner.connection.driver.createParameter(\n\t\t\t\t\t\t'parent_entity_' + column.referencedColumn!.databaseName,\n\t\t\t\t\t\tqueryParams.length - 1,\n\t\t\t\t\t);\n\t\t\t\t\treturn `${columnName} = ${parameterName}`;\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tawait this.queryRunner.query(\n\t\t\t\t`INSERT INTO ${tableName} (${[...ancestorColumnNames, ...descendantColumnNames].join(\n\t\t\t\t\t', ',\n\t\t\t\t)}) ` +\n\t\t\t\t\t`SELECT ${ancestorColumnNames.join(', ')}, ${childEntityIds1.join(\n\t\t\t\t\t\t', ',\n\t\t\t\t\t)} FROM ${tableName} WHERE ${whereCondition.join(' AND ')}`,\n\t\t\t\tqueryParams,","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/typeorm/src/persistence/tree/ClosureSubjectExecutor.ts#L67-L103","documentation":"For closure-table trees, `ClosureSubjectExecutor` inserts the ancestor/descendant rows linking a child to its parent. For each closure-junction descendant column it reads the parent's value via `referencedColumn.getEntityValue(parent)`; if that value is falsy (no parent id), the parent was never persisted and the link cannot be written, so it throws `CannotAttachTreeChildrenEntityError`.","triggerScenarios":"Saving a tree child whose parent is a brand-new entity not yet flushed, so the parent has no id. Calling `treeRepository.save(child)` after assigning `child.parent = new ParentEntity()` without saving the parent first.","commonSituations":"Building the whole tree in memory then saving leaf-first instead of root-first. Forgetting to await the parent's save before saving children. A parent loaded from a query whose PK column wasn't selected.","solutions":["Save the parent first and await it, then assign it to the child and save the child: `await repo.save(parent); child.parent = parent; await repo.save(child);`","Use `TreeRepository.save` on the root of a fully-built tree so TypeORM persists in root-first order.","Ensure the parent's primary key column is selected/loaded (not projected away)."],"exampleFix":"// before\nconst parent = new Category(); parent.name = 'root';\nconst child = new Category(); child.name = 'sub'; child.parent = parent;\nawait repo.save(child); // parent has no id yet → error\n\n// after\nawait repo.save(parent);\nchild.parent = parent;\nawait repo.save(child);","handlingStrategy":"validation","validationCode":"// Before saving a tree child, ensure its parent has an id\nconst parentPk = dataSource.getMetadata(Parent).primaryColumns.map(c => c.getEntityValue(child.parent));\nif (parentPk.some(v => v == null)) {\n  throw new Error('Parent has no id — save the parent before the child');\n}","typeGuard":"function parentHasId<P>(parent: P, pk: keyof P): parent is P & Record<typeof pk, NonNullable<P[typeof pk]>> {\n  return parent != null && (parent as any)[pk] != null;\n}","tryCatchPattern":"try { await treeRepo.save(child); } catch (e) { if (e instanceof CannotAttachTreeChildrenEntityError) { /* await save(parent) first */ } throw e; }","preventionTips":["Always save root-first when building a tree in memory.","Use TreeRepository.save on the root of a fully-built tree.","Ensure find queries for parents select the primary key column."],"tags":["typeorm","tree","closure-table","persistence","parent-child"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}