mrdoob/three.js · error · NodeError

THREE.TSL: No "ConstNode" found in node graph.

Error message

THREE.TSL: No "ConstNode" found in node graph.

What it means

Thrown by RangeNode.getConstNode() when traversing the minNode/maxNode graph yields no node flagged `isConstNode`. RangeNode relies on constant bounds to generate per-instance data for instanced meshes (object.count > 1); a bound that is a dynamic/uniform/runtime node with no ConstNode leaf cannot be evaluated at build time.

Source

Thrown at src/nodes/geometry/RangeNode.js:115

	 * @returns {Node} The constant node, if found.
	 */
	getConstNode( node ) {

		let output = null;

		node.traverse( n => {

			if ( n.isConstNode === true ) {

				output = n;

			}

		} );

		if ( output === null ) {

			throw new NodeError( 'THREE.TSL: No "ConstNode" found in node graph.', this.stackTrace );

		}

		return output;

	}

	setup( builder ) {

		const object = builder.object;

		let output = null;

		if ( object.count > 1 ) {

			const minNode = this.getConstNode( this.minNode );
			const maxNode = this.getConstNode( this.maxNode );

View on GitHub (pinned to da05705fa3)

Solutions

  1. Pass literal values or nodes that resolve to ConstNode (e.g. `float(1)`, `vec3(...)`, raw numbers/Colors) as the range bounds.
  2. If the bound must be dynamic, do not use RangeNode; compute the range in the shader directly with the dynamic node.
  3. Ensure the RangeNode is only used where object.count > 1 with constant bounds.

Example fix

// before
material.colorNode = range( myUniformMin, myUniformMax );

// after
material.colorNode = range( new Color( 0x000000 ), new Color( 0xffffff ) );
Defensive patterns

Strategy: type-guard

Validate before calling

function isConstBound( node ) {
  let found = false;
  node.traverse( n => { if ( n.isConstNode === true ) found = true; } );
  return found;
}

// before using range() on an InstancedMesh:
if ( ! isConstBound( minNode ) || ! isConstBound( maxNode ) ) {
  throw new Error( 'RangeNode bounds must contain a ConstNode' );
}

Type guard

const isConstNode = ( n ) => !! n && n.isConstNode === true;

Prevention

When it happens

Trigger: Calling `range()` (or a node that uses it) on an InstancedMesh where minNode/maxNode is a UniformNode, a runtime expression, or any node whose graph contains no ConstNode; passing a raw number works (it gets wrapped in a ConstNode) but passing an already-wrapped dynamic node does not.

Common situations: Driving per-instance random ranges from a uniform or animated node; reusing a RangeNode built from non-const inputs on a multi-instance object; feeding the output of another node chain as the range bound.

Related errors


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