{"record":{"id":"f59a9c892de245c5","repo":"krahets/hello-algo","slug":"heap-is-empty-f59a9c","errorCode":null,"errorMessage":"Heap is empty","messagePattern":"Heap is empty","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"en/codes/javascript/chapter_heap/my_heap.js","lineNumber":85,"sourceCode":"\n    /* Starting from node i, heapify from bottom to top */\n    #siftUp(i) {\n        while (true) {\n            // Get parent node of node i\n            const p = this.#parent(i);\n            // When \"crossing root node\" or \"node needs no repair\", end heapify\n            if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break;\n            // Swap two nodes\n            this.#swap(i, p);\n            // Loop upward heapify\n            i = p;\n        }\n    }\n\n    /* Element exits heap */\n    pop() {\n        // Handle empty case\n        if (this.isEmpty()) throw new Error('Heap is empty');\n        // Delete node\n        this.#swap(0, this.size() - 1);\n        // Remove node\n        const val = this.#maxHeap.pop();\n        // Return top element\n        this.#siftDown(0);\n        // Return heap top element\n        return val;\n    }\n\n    /* Starting from node i, heapify from top to bottom */\n    #siftDown(i) {\n        while (true) {\n            // If node i is largest or indices l, r are out of bounds, no need to continue heapify, break\n            const l = this.#left(i),\n                r = this.#right(i);\n            let ma = i;\n            if (l < this.size() && this.#maxHeap[l] > this.#maxHeap[ma]) ma = l;","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/en/codes/javascript/chapter_heap/my_heap.js#L67-L103","documentation":"Thrown by pop() on a max-heap when the heap is empty (isEmpty() returns true). pop() swaps root with the last element, removes the last, then sifts down the root. The guard ensures no undefined is returned and no swap against a non-existent index. This is a state guard, not a bounds check on arguments.","triggerScenarios":"Calling heap.pop() on a freshly constructed or fully drained heap; calling pop() more times than the number of pushed elements; interleaving peek()/pop() without tracking size.","commonSituations":"Drain loop that pops until 'falsy' (undefined never reached because throw happens first); event-loop priority queue that processes faster than it receives; forgetting that pop requires prior push.","solutions":["Check heap.isEmpty() / heap.size() === 0 before calling pop.","In a drain loop, use while (!heap.isEmpty()) { const v = heap.pop(); ... }.","Track the count of pushes separately if you need to pop a fixed number.","Wrap pop() in try/catch only as a last resort; prefer the explicit emptiness check."],"exampleFix":"// before\nwhile (true) { const v = heap.pop(); ... } // throws when empty\n\n// after\nwhile (!heap.isEmpty()) { const v = heap.pop(); ... }","handlingStrategy":"validation","validationCode":"if (!heap.isEmpty()) {\n  const v = heap.pop();\n} else {\n  // handle empty heap\n}","typeGuard":"function heapHasElements(heap) {\n  return typeof heap.isEmpty === 'function' && !heap.isEmpty();\n}","tryCatchPattern":"try {\n  const v = heap.pop();\n} catch (e) {\n  if (e.message === 'Heap is empty') { /* drained */ }\n  else throw e;\n}","preventionTips":["Always check isEmpty() before pop().","Drain with while (!heap.isEmpty()) pop().","Track push count to bound a fixed number of pops."],"tags":["heap","priority-queue","empty-state","javascript"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}