From 6679aa7b179e3641a85e3d360f32b82a34bb3cc2 Mon Sep 17 00:00:00 2001 From: Vidit Patankar Date: Sat, 18 Jul 2026 20:20:50 +0530 Subject: [PATCH 1/2] fix: treat [0] document references as out of range in AnswerBuilder References are 1-based, so a [0] citation yields index -1, which Python resolves to the last document instead of triggering the IndexError guard. The unrelated last document was returned marked referenced=True with source_index=0. Use an explicit bounds check so [0] (and expanded ranges starting at 0) warn and attach nothing, like any other out-of-range reference. --- .../components/builders/answer_builder.py | 7 ++-- ...ference-out-of-range-64aab56f8b5f65c3.yaml | 7 ++++ .../builders/test_answer_builder.py | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml diff --git a/haystack/components/builders/answer_builder.py b/haystack/components/builders/answer_builder.py index 78d3ed08d23..a25d3f25ccc 100644 --- a/haystack/components/builders/answer_builder.py +++ b/haystack/components/builders/answer_builder.py @@ -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 diff --git a/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml b/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml new file mode 100644 index 00000000000..793d36cd10a --- /dev/null +++ b/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml @@ -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]`). diff --git a/test/components/builders/test_answer_builder.py b/test/components/builders/test_answer_builder.py index e5bc20d3d92..dfe847b5300 100644 --- a/test/components/builders/test_answer_builder.py +++ b/test/components/builders/test_answer_builder.py @@ -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( From a178be062b72f4dc8eecd601056e4411c4a2fda0 Mon Sep 17 00:00:00 2001 From: Vidit Patankar Date: Sat, 18 Jul 2026 20:25:26 +0530 Subject: [PATCH 2/2] Use double backticks in release note --- ...lder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml b/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml index 793d36cd10a..db8512d1fd7 100644 --- a/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml +++ b/releasenotes/notes/answer-builder-zero-reference-out-of-range-64aab56f8b5f65c3.yaml @@ -1,7 +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]`). + 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]``).