{"record":{"id":"3ad578487aaed3cd","repo":"BabylonJS/Babylon.js","slug":"layer-layer-is-out-of-range-for-a-2d-array-text","errorCode":null,"errorMessage":"Layer ${layer} is out of range for a 2D array texture with ${texture.depth} layers.","messagePattern":"Layer (.+?) is out of range for a 2D array texture with (.+?) layers\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts","lineNumber":61,"sourceCode":"    imageBitmapOptions?: ImageBitmapOptions;\r\n}\r\n\r\n/**\r\n * Uploads a decoded image source (ImageBitmap, canvas, video, image element...) into a single layer of a 2D array texture.\r\n * This is the image-source counterpart to RawTexture2DArray.update, which only accepts raw bytes.\r\n * @param texture defines the 2D array texture to upload into\r\n * @param source defines the image source to upload\r\n * @param layer defines the array layer to upload into\r\n * @param options defines optional upload settings (invertY, premultiplyAlpha)\r\n */\r\nexport function UploadImageToTexture2DArrayLayer(texture: RawTexture2DArray, source: ImageSource, layer: number, options?: IUploadImageToTexture2DArrayLayerOptions): void {\r\n    const internalTexture = texture.getInternalTexture();\r\n    if (!internalTexture) {\r\n        throw new Error(\"Cannot upload to a 2D array texture that has no internal texture.\");\r\n    }\r\n\r\n    if (!Number.isInteger(layer) || layer < 0 || layer >= texture.depth) {\r\n        throw new Error(`Layer ${layer} is out of range for a 2D array texture with ${texture.depth} layers.`);\r\n    }\r\n\r\n    const scene = texture.getScene();\r\n    if (!scene) {\r\n        throw new Error(\"Cannot upload to a 2D array texture that is not attached to a scene.\");\r\n    }\r\n\r\n    const engine = scene.getEngine();\r\n    // updateTextureArrayLayerFromImageSource is an opt-in engine extension. When the consumer never\r\n    // imported it, the augmented method is missing, so fail early with the standard side-effect import\r\n    // message (matching the engine.rawTexture family) instead of a generic \"is not a function\" error.\r\n    if (!_IsSideEffectImplemented(engine.updateTextureArrayLayerFromImageSource)) {\r\n        throw _WarnImport(\"engine.texture2DArrayImageSource\");\r\n    }\r\n\r\n    engine.updateTextureArrayLayerFromImageSource(internalTexture, source, layer, options?.invertY ?? false, options?.premultiplyAlpha ?? false);\r\n}\r\n\r","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts#L43-L79","documentation":"After confirming an internal texture exists, UploadImageToTexture2DArrayLayer validates that the target layer index is a non-negative integer strictly less than the texture's depth (layer count). Any out-of-range or non-integer layer throws with a message naming the requested layer and the texture's layer count.","triggerScenarios":"Calling UploadImageToTexture2DArrayLayer with layer >= texture.depth, a negative layer, a fractional layer, or NaN — e.g. indexing into an array texture built from N images with layer N (off-by-one) or a parsed string index.","commonSituations":"Off-by-one loops over layers, parseInt results, indices derived from a different texture's depth, or mixing up 0-based vs 1-based layer numbering.","solutions":["Clamp/validate layer to the range [0, texture.depth - 1] before uploading","Fix off-by-one loop bounds when uploading layers sequentially","Coerce string indices with Number() and check Number.isInteger","Log texture.depth at the call site to confirm expected layer count"],"exampleFix":"// before\nUploadImageToTexture2DArrayLayer(tex, bitmaps[i], i + 1);\n// after\nif (i + 1 < tex.depth) UploadImageToTexture2DArrayLayer(tex, bitmaps[i], i + 1);","handlingStrategy":"validation","validationCode":"function uploadLayer(tex, source, layer) {\n  if (!Number.isInteger(layer) || layer < 0 || layer >= tex.depth) {\n    throw new RangeError(`layer ${layer} out of [0, ${tex.depth})`);\n  }\n  UploadImageToTexture2DArrayLayer(tex, source, layer);\n}","typeGuard":"function isValidLayer(layer: unknown, depth: number): layer is number {\n  return typeof layer === \"number\" && Number.isInteger(layer) && layer >= 0 && layer < depth;\n}","tryCatchPattern":"try {\n  UploadImageToTexture2DArrayLayer(tex, bitmap, layer);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"out of range\")) {\n    console.error(`Bad layer ${layer}; texture depth=${tex.depth}`);\n  } else throw e;\n}","preventionTips":["Clamp layer indices to [0, depth - 1]","Check loop bounds for off-by-one errors","Convert string indices to integers and validate"],"tags":["texture","argument-validation","off-by-one"],"backgroundTag":"index-out-of-range","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}