BabylonJS/Babylon.js · error · Error

Failed to decode the KTX2 file: layer ${mipmap.layerIndex} o

Error message

Failed to decode the KTX2 file: layer ${mipmap.layerIndex} of the base mip level is ${mipmap.width}x${mipmap.height} but layer 0 is ${width}x${height}.

What it means

All layers of a KTX2 2D array texture's base mip must have identical dimensions, since they are uploaded as one array texture. This error is thrown when a decoded layer's width/height differs from layer 0.

Source

Thrown at packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts:183

    // the first layerCount entries and its layers are already in ascending order.
    const baseLevel = decodedData.mipmaps.slice(0, layerCount);

    if (baseLevel.length !== layerCount) {
        throw new Error(`Failed to decode the KTX2 file: expected ${layerCount} layers for the base mip level but got ${baseLevel.length}.`);
    }

    // Every layer of a level shares the level's dimensions, and forceRGBA above means each one must be exactly
    // width * height * 4 bytes. RawTexture2DArray takes all the layers as one flat buffer and cannot detect a
    // short or mismatched layer, so validate here rather than uploading malformed data.
    const { width, height } = baseLevel[0];
    const expectedLayerByteLength = width * height * 4;

    for (const mipmap of baseLevel) {
        if (!mipmap.data) {
            throw new Error(`Failed to decode the KTX2 file: layer ${mipmap.layerIndex} of the base mip level is empty.`);
        }
        if (mipmap.width !== width || mipmap.height !== height) {
            throw new Error(
                `Failed to decode the KTX2 file: layer ${mipmap.layerIndex} of the base mip level is ${mipmap.width}x${mipmap.height} but layer 0 is ${width}x${height}.`
            );
        }
        if (mipmap.data.byteLength !== expectedLayerByteLength) {
            throw new Error(
                `Failed to decode the KTX2 file: layer ${mipmap.layerIndex} of the base mip level holds ${mipmap.data.byteLength} bytes but ${expectedLayerByteLength} were expected.`
            );
        }
    }

    // A 2D array texture is uploaded as a single buffer holding every layer back to back.
    const textureData = new Uint8Array(expectedLayerByteLength * layerCount);
    let byteOffset = 0;
    for (const mipmap of baseLevel) {
        textureData.set(mipmap.data!, byteOffset);
        byteOffset += mipmap.data!.byteLength;
    }

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Re-encode the KTX2 array ensuring every source image is resized to the same width/height before packing.
  2. Verify the exporter/pipeline output dimensions with a KTX2 inspector (e.g. toktx --basetype or ktxinfo).
  3. If layers must differ, use separate textures or render them per-frame instead of a 2D array texture.

Example fix

// before: packing mixed-resolution sources
await packKtx2([imgA_512, imgB_256]);
// after: normalize sizes first
const normalized = sources.map(img => resize(img, 512, 512));
await packKtx2(normalized);
Defensive patterns

Strategy: validation

Validate before calling

// Check source images share dimensions before packing a KTX2 array
for (const img of layers) {
  if (img.width !== layers[0].width || img.height !== layers[0].height) {
    throw new Error(`Layer ${img.name} is ${img.width}x${img.height}, expected ${layers[0].width}x${layers[0].height}`);
  }
}

Type guard

function allSameSize(images: { width: number; height: number }[]): boolean {
  return images.every(i => i.width === images[0].width && i.height === images[0].height);
}

Try / catch

try {
  const tex = await CreateTexture2DArrayFromKTX2Async(url, scene);
} catch (e) {
  if (String(e.message).includes("base mip level is")) {
    console.error("KTX2 layers have inconsistent dimensions — re-export asset.");
  }
}

Prevention

When it happens

Trigger: Calling CreateTexture2DArrayFromKTX2Async with a KTX2 file whose array layers were encoded with inconsistent dimensions at the base mip level.

Common situations: Hand-assembled KTX2 arrays where slices of different resolutions were combined, broken exporter scripts, image sets generated at mixed resolutions before packing.

Understand the failure class

Related errors


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