{"record":{"id":"42569241c7dfbfb7","repo":"krahets/hello-algo","slug":"heap-is-empty-425692","errorCode":null,"errorMessage":"Heap is empty","messagePattern":"Heap is empty","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"en/codes/python/chapter_heap/my_heap.py","lineNumber":77,"sourceCode":"\n    def sift_up(self, i: int):\n        \"\"\"Starting from node i, heapify from bottom to top\"\"\"\n        while True:\n            # Get parent node of node i\n            p = self.parent(i)\n            # When \"crossing root node\" or \"node needs no repair\", end heapify\n            if p < 0 or self.max_heap[i] <= self.max_heap[p]:\n                break\n            # Swap two nodes\n            self.swap(i, p)\n            # Loop upward heapify\n            i = p\n\n    def pop(self) -> int:\n        \"\"\"Element exits heap\"\"\"\n        # Handle empty case\n        if self.is_empty():\n            raise IndexError(\"Heap is empty\")\n        # Swap root node with rightmost leaf node (swap first element with last element)\n        self.swap(0, self.size() - 1)\n        # Delete node\n        val = self.max_heap.pop()\n        # Heapify from top to bottom\n        self.sift_down(0)\n        # Return top element\n        return val\n\n    def sift_down(self, i: int):\n        \"\"\"Starting from node i, heapify from top to bottom\"\"\"\n        while True:\n            # Find node with largest value among i, l, r, denoted as ma\n            l, r, ma = self.left(i), self.right(i), i\n            if l < self.size() and self.max_heap[l] > self.max_heap[ma]:\n                ma = l\n            if r < self.size() and self.max_heap[r] > self.max_heap[ma]:\n                ma = r","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/en/codes/python/chapter_heap/my_heap.py#L59-L95","documentation":"MaxHeap.pop raises IndexError('Heap is empty') when is_empty() is true, i.e. the internal max_heap list contains only the reserved logic and no real elements. The guard precedes the swap-and-sift sequence that would otherwise dereference an empty backing store. It encodes the invariant that you cannot extract a maximum from a heap with zero elements. The explicit check gives a clear message instead of an opaque IndexError from list.pop().","triggerScenarios":"Calling heap.pop() on a freshly constructed empty heap; calling pop() more times than elements were pushed; draining the heap in a while-true loop without an emptiness exit; popping after a prior pop already returned the last element.","commonSituations":"Dijkstra/top-K style loops that pop until empty but forget the guard; draining loops `while True: x = heap.pop()`; reusing a heap object across phases without resetting state awareness; off-by-one in batch extraction counts.","solutions":["Guard the loop with the provided predicate: `while not heap.is_empty(): x = heap.pop()`.","Check emptiness before a single pop: `if not heap.is_empty(): val = heap.pop()`.","Use heap.size() to bound a counted extraction loop.","In try/except form, catch IndexError specifically and break, reserving it for flow control only when a precondition check is impractical."],"exampleFix":"// before\nwhile True:\n    val = heap.pop()  # raises on last iteration\n// after\nwhile not heap.is_empty():\n    val = heap.pop()","handlingStrategy":"validation","validationCode":"if not heap.is_empty():\n    val = heap.pop()","typeGuard":"def heap_nonempty(h) -> bool:\n    return not h.is_empty()","tryCatchPattern":"try:\n    val = heap.pop()\nexcept IndexError:\n    # heap drained; break the extraction loop\n    break","preventionTips":["Always drive drain loops with `while not heap.is_empty()`.","Track extracted count against heap.size() before popping.","Reserve exception-based pop for deliberate flow control only."],"tags":["heap","indexerror","empty-state","python","data-structures"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}