mrdoob/three.js · error · Error
THREE.NodeLibrary: Node class ${ nodeClass.name } is not a c
Error message
THREE.NodeLibrary: Node class ${ nodeClass.name } is not a class. What it means
Thrown by NodeLibrary.addType() when the supplied nodeClass argument is not a function (i.e. not a JS class/constructor). The library maps a type id to a Node constructor, so a non-callable value (undefined, an instance, a plain object, a number) is a programming error. Note: if nodeClass is undefined/null, reading `nodeClass.name` in the message can itself throw — pass a real class.
Source
Thrown at src/renderers/common/nodes/NodeLibrary.js:164
}
/**
* Adds a node class definition for the given type to the provided type library.
*
* @param {Node.constructor} nodeClass - The node class definition.
* @param {number|string} type - The object type.
* @param {Map<number|string,Node.constructor>} library - The type library.
*/
addType( nodeClass, type, library ) {
if ( library.has( type ) ) {
warn( `Redefinition of node ${ type }` );
return;
}
if ( typeof nodeClass !== 'function' ) throw new Error( `THREE.NodeLibrary: Node class ${ nodeClass.name } is not a class.` );
if ( typeof type === 'function' || typeof type === 'object' ) throw new Error( `THREE.NodeLibrary: Base class ${ type } is not a class.` );
library.set( type, nodeClass );
}
/**
* Adds a node class definition for the given class definition to the provided type library.
*
* @param {Node.constructor} nodeClass - The node class definition.
* @param {Node.constructor} baseClass - The class definition.
* @param {WeakMap<Node.constructor, Node.constructor>} library - The type library.
*/
addClass( nodeClass, baseClass, library ) {
if ( library.has( baseClass ) ) {
warn( `Redefinition of node ${ baseClass.name }` );View on GitHub (pinned to da05705fa3)
Solutions
- Ensure the first argument is the class itself (a function), not an instance: `addType(MyNodeClass, type, library)`.
- Check for failed imports — log `nodeClass` before registering; if undefined, fix the import path or circular dependency.
- Reorder module imports so node class modules are fully evaluated before addType is called.
- Mark side-effect-bearing registration modules as sideEffects: false cautiously, or import them eagerly.
Example fix
// before
import { MyNode } from './MyNode.js'; // MyNode is undefined due to circular import
library.addType(MyNode, 42, library.materialNodes); // throws
// after
// fix the circular import so MyNode is defined, then:
library.addType(MyNode, 42, library.materialNodes); Defensive patterns
Strategy: type-guard
Validate before calling
function safeAddType(nodeClass, type, library) {
if (typeof nodeClass !== 'function') {
throw new TypeError(`addType expected a class, got ${typeof nodeClass}`);
}
library.addType(nodeClass, type, library);
} Type guard
function isNodeClass(v) {
return typeof v === 'function' && /^(class |function )/.test(v.toString());
} Try / catch
try {
library.addType(nodeClass, type, library);
} catch (e) {
if (/Node class .* is not a class/.test(e.message)) { console.error('Registration skipped: nodeClass is', nodeClass); /* fix import then re-register */ }
else throw e;
} Prevention
- Log every value you pass to addType during development to catch undefined imports early.
- Break circular imports by lazy-importing node classes inside the registration function.
- Add a typeof guard in your registration wrapper to fail with a clearer message than the library.
When it happens
Trigger: Calling `nodeLibrary.addType(someValue, type, library)` where someValue is undefined (e.g. a failed import), an instance rather than a class, or a primitive. Triggered indirectly by addMaterialNode/addLightNode paths that route through addType.
Common situations: Circular import that evaluated to undefined at registration time. Passing `new MyNode()` instead of `MyNode`. Plugin/extension registration done before the node class module finished loading. Bundler tree-shaking removing a side-effect-only class export.
Related errors
- THREE.TSL: Node element ${ name } is not a function
- THREE.Renderer: .compileComputeAsync() expects a ComputeNode
- THREE.Renderer: .compute() expects a ComputeNode.
- THREE.WebGLTextures: renderTarget.depthTexture must be an in
- THREE.WGSLNodeFunction: Function is not a WGSL code.
AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12).
Data as JSON: /api/errors/53843b60df6fdaa0.
Report an issue: GitHub.