krahets/hello-algo · error · Error

Index out of bounds

Error message

Index out of bounds

What it means

Thrown by get(index) on a custom dynamic-array list (TypeScript). The guard rejects index < 0 or index >= this._size. Note the JSDoc comment mislabels get() as 'Update element'; it is actually a read accessor returning arr[index]. Capacity (backing array length) is irrelevant — only the logical size bounds valid reads.

Source

Thrown at en/codes/typescript/chapter_array_and_linkedlist/my_list.ts:32

    /* Constructor */
    constructor() {
        this.arr = new Array(this._capacity);
    }

    /* Get list length (current number of elements) */
    public size(): number {
        return this._size;
    }

    /* Get list capacity */
    public capacity(): number {
        return this._capacity;
    }

    /* Update element */
    public get(index: number): number {
        // If the index is out of bounds, throw an exception, as below
        if (index < 0 || index >= this._size) throw new Error('Index out of bounds');
        return this.arr[index];
    }

    /* Add elements at the end */
    public set(index: number, num: number): void {
        if (index < 0 || index >= this._size) throw new Error('Index out of bounds');
        this.arr[index] = num;
    }

    /* Direct traversal of list elements */
    public add(num: number): void {
        // If length equals capacity, need to expand
        if (this._size === this._capacity) this.extendCapacity();
        // Add new element to end of list
        this.arr[this._size] = num;
        this._size++;
    }

View on GitHub (pinned to 69932aed18)

Solutions

  1. Guard before read: if (index >= 0 && index < list.size()) { const v = list.get(index); }.
  2. Iterate with for (let i = 0; i < list.size(); i++) (strict <).
  3. Recompute list.size() after mutations rather than caching.
  4. Return a default for empty/invalid indices via a wrapper instead of letting the throw propagate.

Example fix

// before
for (let i = 0; i <= list.size(); i++) { use(list.get(i)); } // throws at i === size

// after
for (let i = 0; i < list.size(); i++) { use(list.get(i)); }
Defensive patterns

Strategy: validation

Validate before calling

function canGet(list, index) {
  return Number.isInteger(index) && index >= 0 && index < list.size();
}
if (canGet(list, i)) { const v = list.get(i); }

Type guard

function isValidReadIndex(list, index) {
  return typeof index === 'number' && Number.isInteger(index) && index >= 0 && index < list.size();
}

Try / catch

try {
  const v = list.get(i);
} catch (e) {
  if (e.message === 'Index out of bounds') { /* bad index */ }
  else throw e;
}

Prevention

When it happens

Trigger: Calling list.get(index) with negative index, index >= list.size(), or reading a position never written. Empty list (size 0) rejects all non-negative indices too.

Common situations: Off-by-one in iteration (using <= instead of <); reading before add(); caching size before mutations; passing unvalidated input directly to get().

Related errors


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