Skip to content

[Bug]: update_communities leaves dangling entity_ids/relationship_ids after an incremental update #2540

Description

@mainpart

Do you need to file an issue?

  • I have searched the existing issues and this bug is not already filed.
  • My model is hosted on OpenAI or Azure. If not, please look at the "model providers" issue and don't file a new one here.
  • I believe this is a legitimate bug, not just a question. If this is a question, please use the Discussions area.

Describe the bug

graphrag update runs the full pipeline over the new document alone, minting fresh UUIDs,
then merges the result into the existing index. The entity merge keeps the pre-existing row
on a title collision, discards the delta UUID and returns a {delta_id: old_id} mapping.
The community merge never receives it, so delta communities are concatenated with their
entity_ids and relationship_ids still pointing at the discarded ids.

Minimal example

Initial graphrag index over document A:

entities      ALPHA id=e-1,  BETA id=e-2
communities   community 0 -> entity_ids [e-1, e-2]

graphrag update with document B, which mentions ALPHA and GAMMA. The delta run has no
knowledge of the existing index, so it mints new ids and clusters its own graph:

delta entities      ALPHA id=d-1,  GAMMA id=d-2
delta communities   community 0 -> entity_ids [d-1, d-2]

After the merge:

entities      ALPHA id=e-1     (d-1 discarded; mapping {d-1: e-1} produced)
              BETA  id=e-2
              GAMMA id=d-2
communities   community 0 -> entity_ids [e-1, e-2]
              community 1 -> entity_ids [d-1, d-2]   <-- d-1 resolves to nothing

Root cause

_group_and_resolve_entities keeps the old row on a title collision and returns
{delta_id: old_id}:

id_mapping = dict(zip(merged["id_B"], merged["id_A"]))   # delta -> old
...
.groupby("title").agg({"id": "first", ...})              # old row wins

The mapping is published to the run state in update_entities_relationships.py, and applied
in exactly one place: update_text_units.py. _update_and_merge_communities never touches
entity_ids or relationship_ids; they ride through the concatenation unchanged.

Relationships are worse off: _update_and_merge_relationships uses the same "id": "first"
collision handling but returns only a DataFrame, so no relationship mapping exists at all.

Impact

  • ALPHA is never linked to community 1, although the report for community 1 was generated
    from ALPHA's delta description and refers to it.
  • communities.size for community 1 says 2; only one member is resolvable.
  • The same applies to relationship_ids for any edge present in both documents.

Related issues

Steps to reproduce

  1. graphrag index a corpus containing at least one entity that will also appear in a second
    document.
  2. Add the second document and run graphrag update.
  3. Read communities.parquet and entities.parquet, and explode entity_ids:
import pandas as pd
e = pd.read_parquet("output/entities.parquet")
c = pd.read_parquet("output/communities.parquet")
exploded = c.explode("entity_ids")
dangling = exploded[~exploded["entity_ids"].isin(set(e["id"]))]
print(dangling[["community", "entity_ids"]])

Every row printed is a community member that no query path can resolve. The count grows with
each subsequent update.

Expected Behavior

Community membership lists should reference the ids that survived the entity and relationship
merges, so that entities carried over from a previous run remain linked to the communities the
delta run placed them in.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions