{"record":{"id":"45bef469b30733f8","repo":"mrdoob/three.js","slug":"three-webgputextureutils-texture-already-initiali","errorCode":null,"errorMessage":"THREE.WebGPUTextureUtils: Texture already initialized.","messagePattern":"THREE\\.WebGPUTextureUtils: Texture already initialized\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderers/webgpu/utils/WebGPUTextureUtils.js","lineNumber":316,"sourceCode":"\t *\n\t * @param {Texture} texture - The texture.\n\t * @param {Object} [options={}] - Optional configuration parameter.\n\t */\n\tcreateTexture( texture, options = {} ) {\n\n\t\tconst backend = this.backend;\n\t\tconst textureData = backend.get( texture );\n\n\t\tif ( textureData.initialized ) {\n\n\t\t\t// Skip creation for external XR textures - they are already set up\n\t\t\tif ( textureData.externalTexture === true ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthrow new Error( 'THREE.WebGPUTextureUtils: Texture already initialized.' );\n\n\t\t}\n\n\t\tif ( texture.isExternalTexture ) {\n\n\t\t\ttextureData.texture = texture.sourceTexture;\n\t\t\ttextureData.initialized = true;\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( options.needsMipmaps === undefined ) options.needsMipmaps = false;\n\t\tif ( options.levels === undefined ) options.levels = 1;\n\t\tif ( options.depth === undefined ) options.depth = 1;\n\n\t\tconst { width, height, depth, levels } = options;\n","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/mrdoob/three.js/blob/da05705fa31f02710c19772a2aa70c7454807f0c/src/renderers/webgpu/utils/WebGPUTextureUtils.js#L298-L334","documentation":"Thrown by WebGPUTextureUtils.createTexture when the backend already holds an initialized GPU texture for the given Texture object (textureData.initialized === true) and it is not an external XR texture. createTexture is the one-time GPU resource allocation path; once a texture is initialized the renderer drives updates through texture.version comparison (textureData.version vs texture.version) inside updateTexture, never by re-calling createTexture. Re-entering createTexture on the same texture would leak/duplicate GPU memory, so the library treats it as a programmer error.","triggerScenarios":"Calling renderer.backend.textureUtils.createTexture(texture) (or the public Renderer path that reaches it) on a texture the renderer has already uploaded. Triggering a forced re-creation while the version bookkeeping still marks the texture initialized. Calling createTexture manually for a texture that is also attached to a scene already rendered once. Reusing a Texture object after dispose without resetting backend state.","commonSituations":"Mixing the high-level renderer API (which owns texture lifecycle via texture.needsUpdate = true) with manual low-level backend.createTexture calls. Hot-reload / HMR flows that re-run setup code on the same Texture instance. Calling createTexture to change a texture's size or format instead of disposing and creating a new Texture. Misusing a texture both as a render target attachment and as a manually-created resource.","solutions":["Drive updates through the public API: set texture.needsUpdate = true (or bump texture.version) and let the renderer's updateTexture path handle re-upload.","If you genuinely need a fresh GPU resource, call texture.dispose() and create a new Texture instance (or reuse it only after the backend state for it has been cleared), not createTexture on the existing initialized one.","If calling backend.createTexture directly, guard with: if (renderer.backend.get(texture).initialized) return; before invoking it.","Remove any double-init code path such as calling createTexture inside a loop or render callback that already runs the normal texture update pipeline."],"exampleFix":"// before: manual re-create after resize\nfunction resize( texture, w, h ) {\n  texture.image.width = w; texture.image.height = h;\n  renderer.backend.textureUtils.createTexture( texture ); // throws once initialized\n}\n\n// after: go through the version-tracked update path\nfunction resize( texture, w, h ) {\n  texture.image.width = w; texture.image.height = h;\n  texture.needsUpdate = true; // renderer re-uploads safely\n}","handlingStrategy":"validation","validationCode":"// Never call backend.createTexture directly without checking the initialized flag.\nfunction safeCreateTexture( renderer, texture, options ) {\n  const data = renderer.backend.get( texture );\n  if ( data && data.initialized ) {\n    // already on GPU: route through the version-tracked update path instead\n    texture.needsUpdate = true;\n    return;\n  }\n  renderer.backend.textureUtils.createTexture( texture, options );\n}","typeGuard":null,"tryCatchPattern":"try {\n  renderer.backend.textureUtils.createTexture( texture );\n} catch ( err ) {\n  if ( /Texture already initialized/.test( err.message ) ) {\n    // texture is already on the GPU; use the update path instead\n    texture.needsUpdate = true;\n  } else {\n    throw err;\n  }\n}","preventionTips":["Prefer texture.needsUpdate = true over any direct backend.createTexture call.","Treat createTexture as a one-shot allocation: to change size or format, dispose the Texture and build a new one.","Keep texture lifecycle ownership in one place (the renderer); do not mix high-level scene rendering with manual backend texture calls.","In HMR / hot-reload flows, dispose and recreate Texture instances rather than re-running createTexture on survivors."],"tags":["webgpu","texture","gpu-resource","lifecycle","double-init"],"backgroundTag":null,"analyzedSha":"da05705fa31f02710c19772a2aa70c7454807f0c","analyzedAt":"2026-08-12T22:51:37.160Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}