{"record":{"id":"307951f37972434b","repo":"mrdoob/three.js","slug":"three-functionoverloadingnode-functionnode-must-b","errorCode":null,"errorMessage":"THREE.FunctionOverloadingNode: FunctionNode must be a layout.","messagePattern":"THREE\\.FunctionOverloadingNode: FunctionNode must be a layout\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/nodes/utils/FunctionOverloadingNode.js","lineNumber":100,"sourceCode":"\tgetCandidateFn( builder ) {\n\n\t\tconst params = this.parametersNodes;\n\n\t\tlet candidateFn = this._candidateFn;\n\n\t\tif ( candidateFn === null ) {\n\n\t\t\tlet bestCandidateFn = null;\n\t\t\tlet bestScore = - 1;\n\n\t\t\tfor ( const functionNode of this.functionNodes ) {\n\n\t\t\t\tconst shaderNode = functionNode.shaderNode;\n\t\t\t\tconst layout = shaderNode.layout;\n\n\t\t\t\tif ( layout === null ) {\n\n\t\t\t\t\tthrow new Error( 'THREE.FunctionOverloadingNode: FunctionNode must be a layout.' );\n\n\t\t\t\t}\n\n\t\t\t\tconst inputs = layout.inputs;\n\n\t\t\t\tif ( params.length === inputs.length ) {\n\n\t\t\t\t\tlet currentScore = 0;\n\n\t\t\t\t\tfor ( let i = 0; i < params.length; i ++ ) {\n\n\t\t\t\t\t\tconst param = params[ i ];\n\t\t\t\t\t\tconst input = inputs[ i ];\n\n\t\t\t\t\t\tif ( param.getNodeType( builder ) === input.type ) {\n\n\t\t\t\t\t\t\tcurrentScore ++;\n","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/mrdoob/three.js/blob/da05705fa31f02710c19772a2aa70c7454807f0c/src/nodes/utils/FunctionOverloadingNode.js#L82-L118","documentation":"Thrown by FunctionOverloadingNode.getCandidateFn() when one of the overloaded FunctionNodes has `shaderNode.layout === null`. Overload resolution reads `layout.inputs` to score candidates by parameter count and type, so every overload must be a layout-bearing (i.e. properly typed/declared) Fn. Inline/anonymous Fn without a declared layout cannot be overloaded.","triggerScenarios":"Passing an inline `Fn(() => {...})` (no layout) as one of the overloads to the overloading node; mixing a layout Fn with non-layout Fns; a Fn whose layout failed to generate because its signature could not be inferred.","commonSituations":"Building overloaded shader functions where some variants are written as compact arrow Fns; using `Fn` with a body that does not declare typed inputs; version change where layout inference became stricter.","solutions":["Define each overload as a typed/layout Fn with an explicit parameter layout (e.g. via GLSL/TSL declaration with typed inputs).","Do not pass anonymous inline Fns to FunctionOverloadingNode; ensure every variant has a resolvable layout.","Check that each Fn's layout is generated (non-null) before constructing the overloading node."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function assertOverloadsHaveLayout( functionNodes ) {\n  for ( const fn of functionNodes ) {\n    if ( fn.shaderNode == null || fn.shaderNode.layout === null ) {\n      throw new Error( 'Every overload Fn must have a non-null layout' );\n    }\n  }\n}","typeGuard":"const overloadHasLayout = ( fn ) => fn?.shaderNode?.layout != null;","tryCatchPattern":null,"preventionTips":["Define every overload as a typed/layout Fn.","Do not pass anonymous inline Fns to FunctionOverloadingNode.","Confirm each Fn's layout generated before building the overload set."],"tags":["function-node","overloading","tsl","layout"],"backgroundTag":null,"analyzedSha":"da05705fa31f02710c19772a2aa70c7454807f0c","analyzedAt":"2026-08-12T22:51:37.160Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}