mrdoob/three.js · error · NodeError

THREE.TSL: `texture( value )` function expects a valid insta

Error message

THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().

What it means

Thrown by TextureNode.setup() when the `value` passed to the TSL `texture()` accessor is not a real THREE.Texture. The guard is `!texture || texture.isTexture !== true`, so the value must be truthy and carry the `isTexture` flag. Note `texture()` defaults its first argument to `EmptyTexture`, so this only fires when the caller explicitly passes `null`/`undefined` or a non-texture object (a Node, a Material, a number, a render target, etc.).

Source

Thrown at src/nodes/accessors/TextureNode.js:362

	}

	/**
	 * Setups texture node by preparing the internal nodes for code generation.
	 *
	 * @param {NodeBuilder} builder - The current node builder.
	 */
	setup( builder ) {

		const properties = builder.getNodeProperties( this );
		properties.referenceNode = this.referenceNode;

		//

		const texture = this.value;

		if ( ! texture || texture.isTexture !== true ) {

			throw new NodeError( 'THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().', this.stackTrace );

		}

		//

		const uvNode = Fn( () => {

			let uvNode = this.uvNode;

			if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) {

				uvNode = builder.context.getUV( this, builder );

			}

			if ( ! uvNode ) uvNode = this.getDefaultUV();

			if ( this.updateMatrix === true ) {

View on GitHub (pinned to da05705fa3)

Solutions

  1. Ensure the first argument to `texture()` is a THREE.Texture instance (or a TextureNode).
  2. If referencing a render target, pass `renderTarget.texture`, not the render target object.
  3. If the texture is loaded asynchronously, defer node construction until the texture exists, or rely on the default `EmptyTexture` by omitting the argument.
  4. Switch to `cubeTexture()` for cube maps and `texture3D()` for 3D textures.

Example fix

// before
material.colorNode = texture( myRenderTarget );

// after
material.colorNode = texture( myRenderTarget.texture );
Defensive patterns

Strategy: type-guard

Validate before calling

import { Texture } from 'three';

function resolveTextureValue( value ) {
  if ( value && value.isTextureNode === true ) return value; // texture node ok
  if ( value && value.isTexture === true ) return value;
  return null; // caller should fall back to a default texture or skip
}

// before building the material graph:
const tex = resolveTextureValue( maybeTexture );
if ( tex === null ) throw new Error( 'texture() requires a THREE.Texture' );

Type guard

const isTextureLike = ( v ) => !! v && ( v.isTexture === true || v.isTextureNode === true );

// usage
material.colorNode = isTextureLike( myTex ) ? texture( myTex ) : texture();

Try / catch

try {
  material.colorNode = texture( value );
  renderer.compileAsync( scene, camera ); // build happens here
} catch ( e ) {
  if ( /expects a valid instance of THREE\.Texture/.test( e.message ) ) {
    material.colorNode = texture( fallbackTexture );
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `texture(null)`, `texture(undefined)`, `texture(someMaterial)`, `texture(someNode)`, or passing a `WebGLRenderTarget` instead of `renderTarget.texture`. Also fires if a texture variable is asynchronously loaded but referenced before assignment completes and the caller passed a placeholder non-texture.

Common situations: Forgetting `.texture` on a RenderTarget/RT (passing the RT object itself); passing a `CubeTexture` to `texture()` instead of `cubeTexture()`; referencing a texture field of a material/uniform that resolves to null at build time; passing a `DataTexture` that failed to construct; mixing up the `textureLoad`/`texture` argument order.

Related errors


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