{"record":{"id":"d88f242a2706a449","repo":"mrdoob/three.js","slug":"three-tsl-node-element-name-is-not-a-functio","errorCode":null,"errorMessage":"THREE.TSL: Node element ${ name } is not a function","messagePattern":"THREE\\.TSL: Node element (.+?) is not a function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/nodes/tsl/TSLCore.js","lineNumber":31,"sourceCode":"\nlet currentStack = null;\n\nconst NodeElements = new Map();\n\n// Extend Node Class for TSL using prototype\n\nexport function addMethodChaining( name, nodeElement ) {\n\n\t// No require StackTrace because this is internal API\n\n\tif ( NodeElements.has( name ) ) {\n\n\t\twarn( `TSL: Redefinition of method chaining '${ name }'.` );\n\t\treturn;\n\n\t}\n\n\tif ( typeof nodeElement !== 'function' ) throw new Error( `THREE.TSL: Node element ${ name } is not a function` );\n\n\tNodeElements.set( name, nodeElement );\n\n\tif ( name !== 'assign' ) {\n\n\t\t// Changing Node prototype to add method chaining\n\n\t\tNode.prototype[ name ] = function ( ...params ) {\n\n\t\t\t//if ( name === 'toVarIntent' ) return this;\n\n\t\t\treturn this.isStackNode ? this.addToStack( nodeElement( ...params ) ) : nodeElement( this, ...params );\n\n\t\t};\n\n\t\t// Adding assign method chaining\n\n\t\tNode.prototype[ name + 'Assign' ] = function ( ...params ) {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/mrdoob/three.js/blob/da05705fa31f02710c19772a2aa70c7454807f0c/src/nodes/tsl/TSLCore.js#L13-L49","documentation":"Thrown by TSLCore.addMethodChaining() when registering a TSL method whose `nodeElement` is not a function. This is an internal registration API used to wire method chaining onto Node.prototype. A non-function value (undefined, an object, a string) means the chaining call `nodeElement(...)` would fail, so it is rejected upfront.","triggerScenarios":"A plugin/extension calling `addMethodChaining(name, value)` with an undefined import (wrong/default import), an object instead of a factory function, or a typo'd variable; a bundler tree-shaking a named export to undefined.","commonSituations":"Writing a TSL extension that registers custom methods; importing a node element from the wrong path so it resolves to undefined; version mismatch where an export was renamed or removed.","solutions":["Pass a function (typically a `nodeProxy(SomeNode)` factory) as the second argument.","Verify the imported symbol exists and is a function before registering it.","Check the import path and export name against the current Three.js version."],"exampleFix":"// before\nimport { SomeNode } from './SomeNode.js';\naddMethodChaining( 'some', SomeNode ); // SomeNode is a class, not a factory\n\n// after\nimport { SomeNode } from './SomeNode.js';\naddMethodChaining( 'some', nodeProxy( SomeNode ) );","handlingStrategy":"type-guard","validationCode":"function registerMethod( name, nodeElement ) {\n  if ( typeof nodeElement !== 'function' ) {\n    throw new TypeError( `Cannot register '${ name }': nodeElement is not a function` );\n  }\n  addMethodChaining( name, nodeElement );\n}","typeGuard":"const isNodeElementFactory = ( v ) => typeof v === 'function';","tryCatchPattern":null,"preventionTips":["Always pass a nodeProxy(...) factory (a function) to addMethodChaining.","Verify imports resolve to a function before registering.","Re-check export names after Three.js upgrades."],"tags":["tsl","internal-api","plugin","registration"],"backgroundTag":null,"analyzedSha":"da05705fa31f02710c19772a2aa70c7454807f0c","analyzedAt":"2026-08-12T22:51:37.160Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}