deepset-ai/haystack · error · ValueError

top_k must not be negative.

Error message

top_k must not be negative.

What it means

DocumentJoiner.run raises ValueError when the runtime top_k argument is negative. top_k truncates the joined document list; negative values are rejected before slicing. (Runtime top_k may be 0, unlike the init check which requires > 0.)

Source

Thrown at haystack/components/joiners/document_joiner.py:174

        :raises ValueError:
            If `top_k` is negative.
        """
        documents = list(documents)
        output_documents = self.join_mode_function(documents)

        if self.sort_by_score:
            output_documents = sorted(
                output_documents, key=lambda doc: doc.score if doc.score is not None else -inf, reverse=True
            )
            if any(doc.score is None for doc in output_documents):
                logger.info(
                    "Some of the Documents DocumentJoiner got have score=None. It was configured to sort Documents by "
                    "score, so those with score=None were sorted as if they had a score of -infinity."
                )

        if top_k is not None:
            if top_k < 0:
                raise ValueError("top_k must not be negative.")
            output_documents = output_documents[:top_k]
        elif self.top_k is not None:
            output_documents = output_documents[: self.top_k]

        return {"documents": output_documents}

    @staticmethod
    def _concatenate(document_lists: list[list[Document]]) -> list[Document]:
        """
        Concatenate multiple lists of Documents and return only the Document with the highest score for duplicates.
        """
        output = []
        docs_per_id = defaultdict(list)
        for doc in itertools.chain.from_iterable(document_lists):
            docs_per_id[doc.id].append(doc)
        for docs in docs_per_id.values():
            doc_with_best_score = max(docs, key=lambda doc: doc.score if doc.score is not None else -inf)
            output.append(doc_with_best_score)

View on GitHub (pinned to e318778c9b)

Solutions

  1. Pass top_k=None in run() to use the init-time top_k or keep all documents.
  2. Ensure the runtime top_k is >= 0.
  3. Clamp with max(0, top_k) before calling run().

Example fix

// before
joiner.run(documents=docs, top_k=-1)
// after
joiner.run(documents=docs, top_k=None)  # or a non-negative int
Defensive patterns

Strategy: validation

Validate before calling

if run_top_k is not None and run_top_k < 0:
    raise ValueError(f"runtime top_k must be >= 0 or None, got {run_top_k}")
joiner.run(documents=docs, top_k=run_top_k)

Type guard

def is_valid_run_top_k(v: int | None) -> bool:
    return v is None or (isinstance(v, int) and v >= 0)

Try / catch

try:
    out = joiner.run(documents=docs, top_k=k)
except ValueError as e:
    logger.warning("bad runtime top_k: %s", e)
    out = joiner.run(documents=docs, top_k=None)

Prevention

When it happens

Trigger: document_joiner.run(documents=..., top_k=-1) or any negative int at runtime.

Common situations: Using -1 as a 'no limit' sentinel; deriving top_k from user input or config without validation; confusing the stricter init rule (must be > 0) with the looser runtime rule (>= 0).

Understand the failure class

Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/1c5c28be969a0619. Report an issue: GitHub.