mrdoob/three.js · error · Error
THREE.Renderer: .compileComputeAsync() expects a ComputeNode
Error message
THREE.Renderer: .compileComputeAsync() expects a ComputeNode.
What it means
Thrown by Renderer.compileComputeAsync() when the computeNodes argument is not a ComputeNode (or an array of them). The method accepts a single ComputeNode or an array, but every element must be a non-null object with isComputeNode === true; undefined/null/non-ComputeNode values are rejected.
Source
Thrown at src/renderers/common/Renderer.js:1131
* phenomenon which is called "shader compilation stutter", which occurs when
* rendering an object with a new shader for the first time.
*
* @async
* @param {Node|Array<Node>} computeNodes - The compute node(s).
* @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress.
* @return {Promise} A Promise that resolves when the compile has been finished.
*/
async compileComputeAsync( computeNodes, onProgress = null ) {
if ( this._isDeviceLost === true ) return;
if ( this._initialized === false ) await this.init();
const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ];
if ( computeList.length === 0 || computeList.some( ( computeNode ) => computeNode === undefined || computeNode === null || computeNode.isComputeNode !== true ) ) {
throw new Error( 'THREE.Renderer: .compileComputeAsync() expects a ComputeNode.' );
}
const total = computeList.length;
let loaded = 0;
//
const pipelines = this._pipelines;
const bindings = this._bindings;
const nodes = this._nodes;
for ( const computeNode of computeList ) {
if ( pipelines.has( computeNode ) === false ) {
const dispose = () => {
View on GitHub (pinned to da05705fa3)
Solutions
- Construct a ComputeNode via Fn/instancing or new THREE.ComputeNode(...) and pass that instance.
- If passing an array, filter out null/undefined first: nodes.filter(n => n && n.isComputeNode).
- Verify node && node.isComputeNode === true before calling compileComputeAsync.
- Ensure the compute node import path matches your three.js version (Nodes API changed across releases).
Example fix
// before
await renderer.compileComputeAsync( computePipeline ); // not a ComputeNode
// after
import { Fn, instanceIndex } from 'three/tsl';
const computeNode = Fn( () => { /* ... */ } ).compute( count );
await renderer.compileComputeAsync( computeNode ); Defensive patterns
Strategy: type-guard
Validate before calling
const list = ( Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ] ) .filter( n => n && n.isComputeNode === true ); if ( list.length ) await renderer.compileComputeAsync( list );
Type guard
function isComputeNode( node ) {
return node != null && node.isComputeNode === true;
} Prevention
- Construct nodes via TSL Fn(...).compute(count) or new THREE.ComputeNode.
- Filter arrays to remove null/undefined before passing.
- Verify node.isComputeNode === true before compile.
- Ensure compute node imports match your three.js version.
When it happens
Trigger: Passing a NodeMaterial, a compute pipeline object, undefined, null, or a plain object to compileComputeAsync; passing an array that contains a null/undefined element; referencing a compute node variable that was never assigned.
Common situations: Migrating from WebGLRenderer to the WebGPU/Nodes Renderer and confusing compute node APIs; passing the result of an async initializer that resolved to undefined; array filters that leave holes.
Related errors
- THREE.Renderer: .compute() expects a ComputeNode.
- THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinat
- THREE.Renderer: .render() called before the backend is initi
- THREE.Renderer: "getArrayBufferAsync()" offset and count mus
- THREE.Renderer: .hasFeature() called before the backend is i
AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12).
Data as JSON: /api/errors/90fa22dff6351730.
Report an issue: GitHub.