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
- Re-encode the KTX2 array ensuring every source image is resized to the same width/height before packing.
- Verify the exporter/pipeline output dimensions with a KTX2 inspector (e.g. toktx --basetype or ktxinfo).
- 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
- Normalize all source images to one resolution in the asset pipeline before KTX2 packing.
- Inspect packed KTX2 files (ktxinfo/toktx) as a build step.
- Never hand-assemble KTX2 arrays from mixed-resolution sources.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to decode the KTX2 file: layer ${mipmap.layerIndex} o
- All images must share the same dimensions. Image at index ${
- Failed to decode the KTX2 file: expected ${layerCount} layer
- Failed to decode the KTX2 file: layer ${mipmap.layerIndex} o
- SOG texture contains ${splatTexelCount} texels, but metadata
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/e9d896b33be64b1f.
Report an issue: GitHub.