BabylonJS/Babylon.js · error

${method}: local range [${offset}, ${offset + count}) is out

Error message

${method}: local range [${offset}, ${offset + count}) is outside the reserved region [0, ${state.capacity})

What it means

Streaming part writes are expressed in local coordinates [0, capacity) of the reserved region; the handle adds the region base internally. assertLocalRange throws when offset/count are non-integers, negative, or offset+count exceeds the part's reserved capacity, preventing a handle from addressing a neighboring part's texels.

Source

Thrown at packages/dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.ts:2194

        const compound = this;
        const applyBounds = () => {
            if (boundsMin.x <= boundsMax.x) {
                proxy.setBoundingInfo(new BoundingInfo(boundsMin.clone(), boundsMax.clone()));
                compound._updateBoundingInfoFromProxies();
            }
        };
        // Rejects any mutating call after the part was removed, so a retained stale handle can't touch a surviving
        // part that inherited this region's (now-reused) part index/base.
        const assertLive = (method: string) => {
            if (state.removed) {
                throw new Error(`${method}: this streaming part has been removed`);
            }
        };
        // Enforces the documented local part boundary [0, capacity) so a handle call can never address another
        // part's atlas region (the region base is added to these local coordinates before use).
        const assertLocalRange = (method: string, offset: number, count: number) => {
            if (!Number.isInteger(offset) || !Number.isInteger(count) || offset < 0 || count < 0 || offset + count > state.capacity) {
                throw new Error(`${method}: local range [${offset}, ${offset + count}) is outside the reserved region [0, ${state.capacity})`);
            }
        };

        const handle: IGaussianSplattingStreamingPart = {
            proxy,
            capacity,
            get partIndex() {
                return state.partIndex;
            },
            get base() {
                return state.base;
            },
            get centersTexture() {
                return compound.centersTexture;
            },
            get covariancesATexture() {
                return compound.covariancesATexture;
            },

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Use offset/count values within the capacity returned by reserveStreamingPart and clamp offset + count to capacity
  2. Validate Number.isInteger(offset) && Number.isInteger(count) && offset >= 0 && count >= 0 before calling
  3. Split large writes into chunks that fit the reserved region

Example fix

// before
part.writeSplats(globalOffset, data); // atlas-level offset
// after
const local = globalOffset - partBase;
if (local >= 0 && local + data.length / 32 <= part.capacity) {
    part.writeSplats(local, data);
}
Defensive patterns

Strategy: validation

Validate before calling

const ok = Number.isInteger(offset) && Number.isInteger(count) && offset >= 0 && count >= 0 && offset + count <= part.capacity;
if (!ok) throw new RangeError(`[${offset}, ${offset + count}) outside [0, ${part.capacity})`);

Type guard

const inRange = (o: number, c: number, cap: number) =>
  Number.isInteger(o) && Number.isInteger(c) && o >= 0 && c >= 0 && o + c <= cap;

Try / catch

try {
  handle.writeSplats(offset, data);
} catch (e) {
  if (String(e).includes('outside the reserved region')) {
    const n = Math.floor((handle.capacity - offset));
    if (n > 0) handle.writeSplats(offset, data.subarray(0, n * 32));
  } else throw e;
}

Prevention

When it happens

Trigger: Calling a part's write method with offset or count beyond the capacity returned when the part was reserved, with fractional values, or with negative values.

Common situations: Assuming capacity equals the full atlas size; off-by-one errors (offset + count == capacity is valid, > capacity is not); reserving a smaller part than the producer emits.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/30cfacab12240588. Report an issue: GitHub.