index_data_points: pydantic model_copy() shallow-copies metadata dict, corrupting multi-field index buckets
Bug
cognee/tasks/storage/index_data_points.py uses data_point.model_copy() (pydantic shallow copy) then mutates indexed_data_point.metadata["index_fields"] = [field_name].
Because model_copy() shallow-copies the metadata dict (the dict itself is shared between the copy and the original), the mutation leaks back into the original data point. When a DataPoint has more than one index_fields entry (e.g. Entity with index_fields=["name", "description"]), every field bucket gets the last field name written:
- The
Entity_namevector table ends up storing the description text instead of the name - Result: name-based retrieval is silently corrupted (all
Entity_namerows contain description content)
Repro
e = Entity(name="A", description="B", id=uuid4())
await index_data_points([e])
# Entity_name.payload.text == "B" (should be "A")
# Entity_description.payload.text == "B" (correct)Root cause
indexed_data_point = data_point.model_copy() # metadata dict SHARED
indexed_data_point.metadata["index_fields"] = [field_name] # mutates the shared dictdata_point.model_copy() → shallow copy → metadata is the same dict object → later loop iterations overwrite index_fields for ALL previously-queued copies.
Fix (what we patched locally)
Deep-copy metadata per bucket:
indexed_data_point = data_point.model_copy()
indexed_data_point.metadata = {**data_point.metadata, "index_fields": [field_name]}This is invisible with single-field index_fields (the common default), which is why it ships undetected. We hit it after registering a second index field on Entity.
Source: topoteretes/cognee