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 holds ${mipmap.data.byteLength} bytes but ${expectedLayerByteLength} were expected.

What it means

Each layer of the base mip level must contain exactly width*height*4 bytes (RGBA8 uncompressed). This error is thrown when a decoded layer's byte length does not match the expected size, indicating the decoder produced data in an unexpected format or size.

Source

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

    }

    // 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;
    }

    return new RawTexture2DArray(
        textureData,
        width,
        height,
        layerCount,

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Ensure the KTX2/basis transcoder WASM files match your @babylonjs/core version (same release line).
  2. Re-export the KTX2 file without unusual supercompression or with a supported output format.
  3. Verify the file is not truncated or corrupted (checksum against the original export).
  4. Update @babylonjs/core to the latest patch where this decode path may be fixed.

Example fix

// before: mismatched transcoder assets
engine._loadFile("old_basis_encoder/basis_transcoder.js");
// after: load the transcoder matching the core version
await scene.getEngine()._ktx2Decoder.initializeAsync(matchingTranscoderUrl);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure layer byte length matches RGBA8 expectation after decode
const expected = width * height * 4;
if (layerData.byteLength !== expected) {
  throw new Error(`Layer holds ${layerData.byteLength} bytes, expected ${expected}`);
}

Type guard

function isExpectedLayerBytes(m: { data: ArrayBuffer | null; width: number; height: number }): boolean {
  return m.data != null && m.data.byteLength === m.width * m.height * 4;
}

Try / catch

try {
  const tex = await CreateTexture2DArrayFromKTX2Async(url, scene);
} catch (e) {
  if (String(e.message).includes("were expected")) {
    console.error("Transcoder output format mismatch — check transcoder WASM version.");
  }
}

Prevention

When it happens

Trigger: Calling CreateTexture2DArrayFromKTX2Async where the transcoded base-level layer data byte length differs from width*height*4 — e.g. mismatched transcoder output format, partially decoded layer, or corrupt file.

Common situations: Version mismatch between the Babylon.js core and the loaded basis/KTX2 transcoder WASM, misconfigured transcoder formats (e.g. requesting a compressed output the array path doesn't expect), corrupted assets.

Understand the failure class

Related errors


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