Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions haystack/components/builders/answer_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,14 @@ def run(
)

for idx in doc_idxs:
try:
doc = documents[idx]
except IndexError:
# An explicit bounds check is needed because references are 1-based: a reference like [0]
# yields idx = -1, which Python would otherwise silently resolve to the last document.
if not 0 <= idx < len(documents):
logger.warning(
"Document index '{index}' referenced in Generator output is out of range. ", index=idx + 1
)
continue
doc = documents[idx]

doc_meta: dict[str, Any] = dict(doc.meta or {})
doc_meta["source_index"] = idx + 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
AnswerBuilder now treats a ``[0]`` document reference as out of range instead of silently attaching
the last document. References are 1-based, so ``[0]`` produced a negative index that bypassed the
out-of-range guard, marking an unrelated document as ``referenced`` with a wrong ``source_index``.
The same applied to expanded reference ranges starting at 0 (e.g. ``[0-1]``).
32 changes: 32 additions & 0 deletions test/components/builders/test_answer_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,38 @@ def test_run_with_documents_with_reference_pattern_and_no_match(self, caplog):
assert len(answers[0].documents) == 0
assert "Document index '3' referenced in Generator output is out of range." in caplog.text

def test_run_with_documents_with_zero_reference(self, caplog):
# References are 1-based, so [0] is out of range and must not silently
# resolve to the last document via a negative index.
component = AnswerBuilder(reference_pattern="\\[(\\d+)\\]")
with caplog.at_level(logging.WARNING):
output = component.run(
query="test query",
replies=["Answer: AnswerString[0]"],
meta=[{}],
documents=[Document(content="test doc 1"), Document(content="test doc 2")],
)
answers = output["answers"]
assert len(answers) == 1
assert len(answers[0].documents) == 0
assert "Document index '0' referenced in Generator output is out of range." in caplog.text

def test_run_with_zero_reference_in_expanded_range(self, caplog):
component = AnswerBuilder(reference_pattern="\\[([\\d\\s,-]+)\\]", expand_reference_ranges=True)
with caplog.at_level(logging.WARNING):
output = component.run(
query="test query",
replies=["Answer: AnswerString[0-1]"],
meta=[{}],
documents=[Document(content="test doc 1"), Document(content="test doc 2")],
)
answers = output["answers"]
assert len(answers) == 1
assert len(answers[0].documents) == 1
assert answers[0].documents[0].content == "test doc 1"
assert answers[0].documents[0].meta["referenced"] is True
assert "Document index '0' referenced in Generator output is out of range." in caplog.text

def test_run_with_reference_pattern_set_at_runtime(self):
component = AnswerBuilder(reference_pattern="unused pattern")
output = component.run(
Expand Down
Loading