mrdoob/three.js · error · Error

THREE.WebGPUTextureUtils: Texture already initialized.

Error message

THREE.WebGPUTextureUtils: Texture already initialized.

What it means

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.

Source

Thrown at src/renderers/webgpu/utils/WebGPUTextureUtils.js:316

	 *
	 * @param {Texture} texture - The texture.
	 * @param {Object} [options={}] - Optional configuration parameter.
	 */
	createTexture( texture, options = {} ) {

		const backend = this.backend;
		const textureData = backend.get( texture );

		if ( textureData.initialized ) {

			// Skip creation for external XR textures - they are already set up
			if ( textureData.externalTexture === true ) {

				return;

			}

			throw new Error( 'THREE.WebGPUTextureUtils: Texture already initialized.' );

		}

		if ( texture.isExternalTexture ) {

			textureData.texture = texture.sourceTexture;
			textureData.initialized = true;

			return;

		}

		if ( options.needsMipmaps === undefined ) options.needsMipmaps = false;
		if ( options.levels === undefined ) options.levels = 1;
		if ( options.depth === undefined ) options.depth = 1;

		const { width, height, depth, levels } = options;

View on GitHub (pinned to da05705fa3)

Solutions

  1. Drive updates through the public API: set texture.needsUpdate = true (or bump texture.version) and let the renderer's updateTexture path handle re-upload.
  2. 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.
  3. If calling backend.createTexture directly, guard with: if (renderer.backend.get(texture).initialized) return; before invoking it.
  4. Remove any double-init code path such as calling createTexture inside a loop or render callback that already runs the normal texture update pipeline.

Example fix

// before: manual re-create after resize
function resize( texture, w, h ) {
  texture.image.width = w; texture.image.height = h;
  renderer.backend.textureUtils.createTexture( texture ); // throws once initialized
}

// after: go through the version-tracked update path
function resize( texture, w, h ) {
  texture.image.width = w; texture.image.height = h;
  texture.needsUpdate = true; // renderer re-uploads safely
}
Defensive patterns

Strategy: validation

Validate before calling

// Never call backend.createTexture directly without checking the initialized flag.
function safeCreateTexture( renderer, texture, options ) {
  const data = renderer.backend.get( texture );
  if ( data && data.initialized ) {
    // already on GPU: route through the version-tracked update path instead
    texture.needsUpdate = true;
    return;
  }
  renderer.backend.textureUtils.createTexture( texture, options );
}

Try / catch

try {
  renderer.backend.textureUtils.createTexture( texture );
} catch ( err ) {
  if ( /Texture already initialized/.test( err.message ) ) {
    // texture is already on the GPU; use the update path instead
    texture.needsUpdate = true;
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12). Data as JSON: /api/errors/45bef469b30733f8. Report an issue: GitHub.