#4491·cognee

index_data_points: pydantic model_copy() shallow-copies metadata dict, corrupting multi-field index buckets

Author: vincentxu37-dotcomCreated Aug 14, 2026Updated Sep 10, 2026

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_name vector table ends up storing the description text instead of the name
  • Result: name-based retrieval is silently corrupted (all Entity_name rows contain description content)

Repro

python
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

python
indexed_data_point = data_point.model_copy()          # metadata dict SHARED
indexed_data_point.metadata["index_fields"] = [field_name]  # mutates the shared dict

data_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:

python
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.