From efafcff4b216d432241c4b14523929200f7d2340 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Wed, 11 Mar 2026 23:41:25 -0400 Subject: [PATCH] fix: topological insert for KB import nodes to satisfy parent FK Nodes with parent_node_id references were inserted in a single batch, causing FK violations when children were inserted before their parents. Now inserts roots first, flushes, then children in subsequent passes. Co-Authored-By: Claude Opus 4.6 --- backend/app/core/kb_conversion_service.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/app/core/kb_conversion_service.py b/backend/app/core/kb_conversion_service.py index 01a8f40f..69d3a4b5 100644 --- a/backend/app/core/kb_conversion_service.py +++ b/backend/app/core/kb_conversion_service.py @@ -498,9 +498,25 @@ async def convert_document( await db.flush() return [] - # Persist nodes - for node in nodes: - db.add(node) + # Persist nodes — insert roots first to satisfy parent_node_id FK, + # then children in subsequent passes until all are inserted. + remaining = list(nodes) + inserted_ids: set[Any] = set() + while remaining: + batch = [ + n for n in remaining + if n.parent_node_id is None or n.parent_node_id in inserted_ids + ] + if not batch: + # Circular reference or orphan — force insert remaining to surface the real error + for n in remaining: + db.add(n) + break + for n in batch: + db.add(n) + inserted_ids.add(n.id) + await db.flush() + remaining = [n for n in remaining if n.id not in inserted_ids] # Update import record elapsed_ms = int((time.monotonic() - start_time) * 1000)