{"record":{"id":"893c114faa786100","repo":"BabylonJS/Babylon.js","slug":"cannot-upload-to-a-2d-array-texture-that-is-not-at","errorCode":null,"errorMessage":"Cannot upload to a 2D array texture that is not attached to a scene.","messagePattern":"Cannot upload to a 2D array texture that is not attached to a scene\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts","lineNumber":66,"sourceCode":" * 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\n/**\r\n * Fetches an image from a url, decodes it and uploads it into a single layer of a 2D array texture.\r\n * @param texture defines the 2D array texture to upload into\r\n * @param url defines the url of the image to load\r\n * @param layer defines the array layer to upload into\r","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/rawTexture2DArray.functions.ts#L48-L84","documentation":"Uploading requires the owning scene and its engine to invoke the GPU upload path. If texture.getScene() returns null/undefined the wrapper is detached (or never attached), so the library throws instead of dereferencing the scene.","triggerScenarios":"Calling UploadImageToTexture2DArrayLayer on a texture whose scene reference is gone — e.g. after the texture was disposed and detached, or the texture was constructed without a live scene.","commonSituations":"Uploading in an async callback after the scene was disposed (HMR reload, component unmount), or a texture moved between scenes losing its reference.","solutions":["Ensure the upload happens while the scene is still alive; cancel pending async uploads on scene disposal","Pass a valid Scene when creating the RawTexture2DArray","Recreate the texture attached to the current scene if it was disposed","Check scene.isDisposed before uploading"],"exampleFix":"// before\ncreateImageBitmap(blob).then(b => UploadImageToTexture2DArrayLayer(tex, b, layer));\n// after\ncreateImageBitmap(blob).then(b => {\n  if (tex.isDisposed() || !tex.getScene()) return;\n  UploadImageToTexture2DArrayLayer(tex, b, layer);\n});","handlingStrategy":"validation","validationCode":"const scene = texture.getScene();\nif (!scene || scene.isDisposed) {\n  console.warn(\"Skipping upload: texture not attached to a live scene\");\n} else {\n  UploadImageToTexture2DArrayLayer(texture, bitmap, layer);\n}","typeGuard":"function isAttachedToLiveScene(t: RawTexture2DArray): boolean {\n  const s = t.getScene();\n  return !!s && !s.isDisposed;\n}","tryCatchPattern":"try {\n  UploadImageToTexture2DArrayLayer(tex, bitmap, 0);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"not attached to a scene\")) {\n    // scene disposed (e.g. HMR/unmount) — abort upload quietly\n  } else throw e;\n}","preventionTips":["Cancel pending async uploads when the scene disposes","Check texture.getScene() in async callbacks before uploading","Recreate textures after scene reload/HMR instead of reusing"],"tags":["texture","scene","lifecycle"],"backgroundTag":"texture-detached-from-scene","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}