{"record":{"id":"2fe8ec371f6604ae","repo":"deepset-ai/haystack","slug":"pop-from-empty-queue","errorCode":null,"errorMessage":"pop from empty queue","messagePattern":"pop from empty queue","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"haystack/core/pipeline/utils.py","lineNumber":124,"sourceCode":"            Priority level for the item. Lower numbers indicate higher priority.\n        \"\"\"\n        next_count = next(self._counter)\n        entry = (priority, next_count, item)\n        heapq.heappush(self._queue, entry)\n\n    def pop(self) -> tuple[int, Any]:\n        \"\"\"\n        Remove and return the highest priority item from the queue.\n\n        For items with equal priority, returns the one that was inserted first.\n\n        :returns:\n            A tuple containing (priority, item) with the lowest priority number.\n        :raises IndexError:\n            If the queue is empty.\n        \"\"\"\n        if not self._queue:\n            raise IndexError(\"pop from empty queue\")\n        priority, _, item = heapq.heappop(self._queue)\n        return priority, item\n\n    def peek(self) -> tuple[int, Any]:\n        \"\"\"\n        Return but don't remove the highest priority item from the queue.\n\n        For items with equal priority, returns the one that was inserted first.\n\n        :returns:\n            A tuple containing (priority, item) with the lowest priority number.\n        :raises IndexError:\n            If the queue is empty.\n        \"\"\"\n        if not self._queue:\n            raise IndexError(\"peek at empty queue\")\n        priority, _, item = self._queue[0]\n        return priority, item","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/core/pipeline/utils.py#L106-L142","documentation":"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.","triggerScenarios":"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().","commonSituations":"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().","solutions":["Use get(), which returns None on an empty queue, instead of pop().","Guard with if not queue.is_empty(): queue.pop() or wrap in try/except IndexError.","Check loop conditions: use the queue's emptiness API rather than exception-driven termination."],"exampleFix":"// before\nwhile True:\n    priority, task = queue.pop()\n// after\nwhile not queue.is_empty():\n    item = queue.get()\n    if item is None:\n        break\n","handlingStrategy":"try-catch","validationCode":"if queue.is_empty():\n    return None","typeGuard":null,"tryCatchPattern":"try:\n    priority, item = queue.pop()\nexcept IndexError:\n    priority, item = None, None","preventionTips":["Prefer the non-raising get() API when draining a queue.","Check is_empty() before destructive operations.","Avoid exception-driven loop termination in scheduler code."],"tags":["queue","indexerror","concurrency","internal-api"],"backgroundTag":"pop-from-empty-queue","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}