krahets/hello-algo · error · Error
Heap is empty
Error message
Heap is empty
What it means
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.
Source
Thrown at en/codes/javascript/chapter_heap/my_heap.js:85
/* Starting from node i, heapify from bottom to top */
#siftUp(i) {
while (true) {
// Get parent node of node i
const p = this.#parent(i);
// When "crossing root node" or "node needs no repair", end heapify
if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break;
// Swap two nodes
this.#swap(i, p);
// Loop upward heapify
i = p;
}
}
/* Element exits heap */
pop() {
// Handle empty case
if (this.isEmpty()) throw new Error('Heap is empty');
// Delete node
this.#swap(0, this.size() - 1);
// Remove node
const val = this.#maxHeap.pop();
// Return top element
this.#siftDown(0);
// Return heap top element
return val;
}
/* Starting from node i, heapify from top to bottom */
#siftDown(i) {
while (true) {
// If node i is largest or indices l, r are out of bounds, no need to continue heapify, break
const l = this.#left(i),
r = this.#right(i);
let ma = i;
if (l < this.size() && this.#maxHeap[l] > this.#maxHeap[ma]) ma = l;View on GitHub (pinned to 69932aed18)
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.
Example fix
// before
while (true) { const v = heap.pop(); ... } // throws when empty
// after
while (!heap.isEmpty()) { const v = heap.pop(); ... } Defensive patterns
Strategy: validation
Validate before calling
if (!heap.isEmpty()) {
const v = heap.pop();
} else {
// handle empty heap
} Type guard
function heapHasElements(heap) {
return typeof heap.isEmpty === 'function' && !heap.isEmpty();
} Try / catch
try {
const v = heap.pop();
} catch (e) {
if (e.message === 'Heap is empty') { /* drained */ }
else throw e;
} Prevention
- Always check isEmpty() before pop().
- Drain with while (!heap.isEmpty()) pop().
- Track push count to bound a fixed number of pops.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of krahets/hello-algo@69932aed18 (2026-08-13).
Data as JSON: /api/errors/f59a9c892de245c5.
Report an issue: GitHub.