Repository: deepset-ai/haystack

Issue:
ExtractiveReader breaks if run with no documents
**Describe the bug**
ExtractiveReader crashes if run with no documents.

**Error message**
```
../../../.asdf/installs/python/3.10.13/lib/python3.10/site-packages/haystack/components/readers/extractive.py:556: in run
    input_ids, attention_mask, sequence_ids, encodings, query_ids, document_ids = self._preprocess(
../../../.asdf/installs/python/3.10.13/lib/python3.10/site-packages/haystack/components/readers/extractive.py:218: in _preprocess
    encodings_pt = self.tokenizer(  # type: ignore
../../../.asdf/installs/python/3.10.13/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:2798: in __call__
    encodings = self._call_one(text=text, text_pair=text_pair, **all_kwargs)
../../../.asdf/installs/python/3.10.13/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:2884: in _call_one
    return self.batch_encode_plus(
../../../.asdf/installs/python/3.10.13/lib/python3.10/site-packages/transformers/tokenization_utils_base.py:3075: in batch_encode_plus
    return self._batch_encode_plus(
../../../.asdf/installs/python/3.10.13/lib/python3.10/site-packages/transformers/models/roberta/tokenization_roberta_fast.py:270: in _batch_encode_plus
    return super()._batch_encode_plus(*args, **kwargs)
...
>       for key in tokens_and_encodings[0][0].keys():
E       IndexError: list index out of range
```

**Expected behavior**
- don't crash my dear

**Additional context**
Add any other context about the problem here, like document types / preprocessing steps / settings of reader etc.

**To Reproduce**
```python
from haystack.components.readers import ExtractiveReader


def test_tobi():
    reader = ExtractiveReader()
    reader.warm_up()
    reader.run(query="hello", documents=[])
```



**FAQ Check**
- [ ] Have you had a look at [our new FAQ page](https://docs.haystack.deepset.ai/docs/faq)?

**System:**
 - OS:
 - GPU/CPU:
 - Haystack version (commit or version number): 2 
 - DocumentStore:
 - Reader:
 - Retriever:



Discussion:

Resolving patch:
diff --git a/haystack/components/readers/extractive.py b/haystack/components/readers/extractive.py
--- a/haystack/components/readers/extractive.py
+++ b/haystack/components/readers/extractive.py
@@ -210,6 +210,7 @@ def _preprocess(
         """
         texts = []
         document_ids = []
+        document_contents = []
         for i, doc in enumerate(documents):
             if doc.content is None:
                 warnings.warn(
@@ -219,9 +220,11 @@ def _preprocess(
                 continue
             texts.append(doc.content)
             document_ids.append(i)
+            document_contents.append(doc.content)
+
         encodings_pt = self.tokenizer(  # type: ignore
             queries,
-            [document.content for document in documents],
+            document_contents,
             padding=True,
             truncation=True,
             max_length=max_seq_length,
@@ -571,6 +574,9 @@ def run(
         :raises ComponentError:
             If the component was not warmed up by calling 'warm_up()' before.
         """
+        if not documents:
+            return {"answers": []}
+
         queries = [query]  # Temporary solution until we have decided what batching should look like in v2
         nested_documents = [documents]
         if self.model is None:


Test patch:
diff --git a/test/components/readers/test_extractive.py b/test/components/readers/test_extractive.py
--- a/test/components/readers/test_extractive.py
+++ b/test/components/readers/test_extractive.py
@@ -266,13 +266,17 @@ def test_from_dict_no_token():
     assert component.token is None
 
 
+def test_run_no_docs(mock_reader: ExtractiveReader):
+    mock_reader.warm_up()
+    assert mock_reader.run(query="hello", documents=[]) == {"answers": []}
+
+
 def test_output(mock_reader: ExtractiveReader):
-    answers = mock_reader.run(example_queries[0], example_documents[0], top_k=3)[
-        "answers"
-    ]  # [0] Uncomment and remove first two indices when batching support is reintroduced
+    answers = mock_reader.run(example_queries[0], example_documents[0], top_k=3)["answers"]
     doc_ids = set()
     no_answer_prob = 1
     for doc, answer in zip(example_documents[0], answers[:3]):
+        assert answer.document_offset is not None
         assert answer.document_offset.start == 11
         assert answer.document_offset.end == 16
         assert doc.content is not None