dotnet/runtime · error · Error

index out of range

Error message

index out of range

What it means

Thrown by WasmRootBufferImpl._throw_index_out_of_range (via _check_in_range) when a get/set/get_address/copy operation is given an index that is < 0 or >= the buffer's capacity. It is the standard bounds-check for the root-buffer array accessors.

Source

Thrown at src/mono/browser/runtime/roots.ts:184

    private __offset: VoidPtr;
    private __offset32: number;
    private __handle: number;
    private __ownsAllocation: boolean;

    constructor (offset: VoidPtr, capacity: number, ownsAllocation: boolean, name?: string) {
        const capacityBytes = capacity * 4;

        this.__offset = offset as any >>> 0 as any;
        this.__offset32 = <number><any>offset >>> 2;
        this.__count = capacity;
        this.length = capacity;
        mono_assert(!WasmEnableThreads || !gc_locked, "GC must not be locked when creating a GC root");
        this.__handle = cwraps.SystemInteropJS_RegisterGCRoot(offset, capacityBytes, name || "noname");
        this.__ownsAllocation = ownsAllocation;
    }

    _throw_index_out_of_range (): void {
        throw new Error("index out of range");
    }

    _check_in_range (index: number): void {
        if ((index >= this.__count) || (index < 0))
            this._throw_index_out_of_range();
    }

    get_address (index: number): MonoObjectRef {
        this._check_in_range(index);
        return <any>this.__offset + (index * 4);
    }

    get_address_32 (index: number): number {
        this._check_in_range(index);
        return this.__offset32 + index;
    }

    // NOTE: These functions do not use the helpers from memory.ts because WasmRoot.get and WasmRoot.set

View on GitHub (pinned to 60108ba66e)

Solutions

  1. Check 0 <= index < buffer.length (or __count) before accessing.
  2. Use exclusive upper bounds in loops: for (let i = 0; i < buf.length; i++).
  3. Ensure the buffer has not been released before indexing into it.

Example fix

// before
for (let i = 0; i <= buf.length; i++) buf.get(i); // off-by-one
// after
for (let i = 0; i < buf.length; i++) buf.get(i);
Defensive patterns

Strategy: validation

Validate before calling

function safeGet(buf: WasmRootBuffer, index: number) {
  if (index < 0 || index >= buf.length) throw new RangeError(`index ${index} out of [0,${buf.length})`);
  return buf.get(index);
}

Type guard

function inRange(buf: { length: number }, i: unknown): i is number {
  return typeof i === 'number' && Number.isInteger(i) && i >= 0 && i < buf.length;
}

Prevention

When it happens

Trigger: Calling buf.get(i), buf.set(i, v), buf.get_address(i), buf.copy_value_from_address(i, ...) with i outside [0, capacity). Common with an off-by-one loop bound or a stale capacity after release().

Common situations: Looping with <= instead of <; using an index computed from a different-sized structure; reading length after the buffer was released (capacity collapses to 0); passing a raw pointer offset where an index was expected.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/a6ce9ba6fade980f. Report an issue: GitHub.