deepset-ai/haystack · error · IndexError

pop from empty queue

Error message

pop from empty queue

What it means

FifoPriorityQueue.pop raises IndexError('pop from empty queue') when called on an empty queue (utils.py:124). Unlike heapq.heappop's bare IndexError, this gives an explicit message. It is an internal scheduling queue used by the pipeline runner's helpers, so hitting it usually means calling pop without checking emptiness.

Source

Thrown at haystack/core/pipeline/utils.py:124

            Priority level for the item. Lower numbers indicate higher priority.
        """
        next_count = next(self._counter)
        entry = (priority, next_count, item)
        heapq.heappush(self._queue, entry)

    def pop(self) -> tuple[int, Any]:
        """
        Remove and return the highest priority item from the queue.

        For items with equal priority, returns the one that was inserted first.

        :returns:
            A tuple containing (priority, item) with the lowest priority number.
        :raises IndexError:
            If the queue is empty.
        """
        if not self._queue:
            raise IndexError("pop from empty queue")
        priority, _, item = heapq.heappop(self._queue)
        return priority, item

    def peek(self) -> tuple[int, Any]:
        """
        Return but don't remove the highest priority item from the queue.

        For items with equal priority, returns the one that was inserted first.

        :returns:
            A tuple containing (priority, item) with the lowest priority number.
        :raises IndexError:
            If the queue is empty.
        """
        if not self._queue:
            raise IndexError("peek at empty queue")
        priority, _, item = self._queue[0]
        return priority, item

View on GitHub (pinned to e318778c9b)

Solutions

  1. Use get(), which returns None on an empty queue, instead of pop().
  2. Guard with if not queue.is_empty(): queue.pop() or wrap in try/except IndexError.
  3. Check loop conditions: use the queue's emptiness API rather than exception-driven termination.

Example fix

// before
while True:
    priority, task = queue.pop()
// after
while not queue.is_empty():
    item = queue.get()
    if item is None:
        break
Defensive patterns

Strategy: try-catch

Validate before calling

if queue.is_empty():
    return None

Try / catch

try:
    priority, item = queue.pop()
except IndexError:
    priority, item = None, None

Prevention

When it happens

Trigger: Calling queue.pop() when is_empty(); race between a size/is_empty check and pop in concurrent code; iterating until peek raises instead of using get().

Common situations: Custom runner code or tests consuming pipeline queue helpers; off-by-one loops around task scheduling; draining a queue with pop instead of the non-raising get().

Related errors


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