krahets/hello-algo · error · RangeError

Heap is empty.

Error message

Heap is empty.

What it means

Thrown by MaxHeap.pop when the heap is empty. pop swaps the root with the last element, removes it, and re-heapifies; with zero elements those steps are meaningless and would return undefined, so the method throws a RangeError to signal the precondition violation.

Source

Thrown at en/codes/typescript/chapter_heap/my_heap.ts:84

    /* Starting from node i, heapify from bottom to top */
    private siftUp(i: number): void {
        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 */
    public pop(): number {
        // Handle empty case
        if (this.isEmpty()) throw new RangeError('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 */
    private siftDown(i: number): void {
        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

  1. Guard every pop with isEmpty() (or size() > 0) first.
  2. Use a while (!heap.isEmpty()) loop for draining.
  3. Return an Option/sentinel from a wrapper instead of letting pop throw.

Example fix

// before
const top = heap.pop(); // throws if empty

// after
const top = heap.isEmpty() ? undefined : heap.pop();
Defensive patterns

Strategy: validation

Validate before calling

const top = heap.isEmpty() ? undefined : heap.pop();

Type guard

function hasElements(h) { return typeof h.isEmpty === 'function' && !h.isEmpty(); }

Try / catch

try { return heap.pop(); }
catch (e) { if (!(e instanceof RangeError)) throw e; return undefined; }

Prevention

When it happens

Trigger: Calling pop on a freshly constructed heap with no inserts; calling pop more times than elements were pushed; interleaving pop with failed pushes so the count is lower than expected.

Common situations: Drain loops that do not check isEmpty; priority-queue consumers that pop on every tick regardless of fill level; off-by-one in loop counters.

Related errors


AI-assisted analysis of krahets/hello-algo@69932aed18 (2026-08-13). Data as JSON: /api/errors/58cc01ee60cb094c. Report an issue: GitHub.