Skip to content

bug: Document.__eq__ ignores colliding metadata keys during equality comparison #11969

Description

@aryanp160

Describe the bug

Document.__eq__ can incorrectly report two Document instances as equal when their metadata contains keys that collide with top-level Document fields (for example id, content, or score).

The current implementation compares the output of Document.to_dict(). Since to_dict() defaults to flatten=True, metadata is flattened into the top-level dictionary and any colliding metadata keys are overwritten by the document's own fields before the equality comparison takes place.

As a result, two documents with different metadata can compare as equal even though their logical state differs.


Error message

No exception is raised.

The issue is silent because the equality comparison simply returns the wrong result.

from haystack import Document

doc1 = Document(
    id="same_id",
    content="hello",
    meta={"id": "different1"},
)

doc2 = Document(
    id="same_id",
    content="hello",
    meta={"id": "different2"},
)

print(doc1 == doc2)

Output:

True

Expected behavior

Documents with different metadata should not compare as equal.

Expected output:

False

Additional context

While investigating this, I verified the following:

  • Document.to_dict(flatten=False) preserves the metadata correctly.
  • The collision only occurs in the flattened representation.
  • Changing Document.__eq__ locally to compare the unflattened representation fixes the issue.
  • I ran the full test/dataclasses/test_document.py suite after making this change, and all existing tests still passed.

I also have a regression test ready if this is considered a bug.


To Reproduce

from haystack import Document

doc1 = Document(
    id="same_id",
    content="hello",
    meta={"id": "different1"},
)

doc2 = Document(
    id="same_id",
    content="hello",
    meta={"id": "different2"},
)

assert doc1 != doc2

Current result:

doc1 == doc2
# True

Expected result:

doc1 == doc2
# False

FAQ Check

  • Have you had a look at the FAQ page?

System

  • OS: Windows 11
  • Haystack version: Current main branch (verified locally)

Metadata

Metadata

Assignees

Labels

P2Medium priority, add to the next sprint if no P1 available

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions