{"record":{"id":"dc44f5b1c0dcce42","repo":"BabylonJS/Babylon.js","slug":"framegraphiblshadowsrenderertask-this-name-d","errorCode":null,"errorMessage":"FrameGraphIblShadowsRendererTask \"${this.name}\": depthTexture, normalTexture, positionTexture and velocityTexture are required","messagePattern":"FrameGraphIblShadowsRendererTask \"(.+?)\": depthTexture, normalTexture, positionTexture and velocityTexture are required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/FrameGraph/Tasks/Rendering/iblShadowsRendererTask.pure.ts","lineNumber":487,"sourceCode":"        // Don't poll for shadow dependencies here.  _tryEnableShadowsTasks() is called\r\n        // in record() (where it imports a placeholder ICDF if the real one isn't ready yet,\r\n        // preventing any \"handle not found\" errors) and by _beforeRenderDependencyObserver\r\n        // on every frame.  Shadows enable automatically once the CDF, environment texture,\r\n        // and blue-noise texture are all ready — no timeout involved.git pu\r\n        return Promise.resolve();\r\n    }\r\n\r\n    public override isReady(): boolean {\r\n        return this._voxelizationTask.isReady() && this._tracingTask.isReady() && this._spatialBlurTask.isReady() && this._accumulationTask.isReady();\r\n    }\r\n\r\n    /**\r\n     * Records the parent task.\r\n     * Child tasks record the actual passes.\r\n     */\r\n    public override record(): void {\r\n        if (this.depthTexture === undefined || this.normalTexture === undefined || this.positionTexture === undefined || this.velocityTexture === undefined) {\r\n            throw new Error(`FrameGraphIblShadowsRendererTask \"${this.name}\": depthTexture, normalTexture, positionTexture and velocityTexture are required`);\r\n        }\r\n\r\n        this._lastImportedIcdfTexture = null;\r\n        this._lastImportedEnvironmentTexture = null;\r\n        this._lastImportedBlueNoiseTexture = null;\r\n\r\n        this._tryEnableShadowsTasks();\r\n\r\n        // Set sub-task texture inputs (these are set here because handles may not be available at construction time)\r\n        this._tracingTask.depthTexture = this.depthTexture;\r\n        this._tracingTask.normalTexture = this.normalTexture;\r\n        this._spatialBlurTask.depthTexture = this.depthTexture;\r\n        this._spatialBlurTask.normalTexture = this.normalTexture;\r\n        this._accumulationTask.positionTexture = this.positionTexture;\r\n        this._accumulationTask.velocityTexture = this.velocityTexture;\r\n\r\n        this._voxelizationTask.record();\r\n        this._tracingTask.record();\r","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/FrameGraph/Tasks/Rendering/iblShadowsRendererTask.pure.ts#L469-L505","documentation":"FrameGraphIblShadowsRendererTask.record() requires all four G-buffer inputs (depthTexture, normalTexture, positionTexture, velocityTexture) to be set, since the IBL shadows renderer samples the full geometry pass data. If any of them is undefined, record() throws instead of recording child passes with missing bindings.","triggerScenarios":"Calling record() (directly or via frameGraph.build()/render loop) on an IblShadowsRendererTask where one or more of depthTexture, normalTexture, positionTexture, velocityTexture was never assigned from an upstream geometry/GBUFFER task's outputs.","commonSituations":"Forgetting to connect a FrameGraphGeometryRenderer/ prepass task outputs to the IBL shadows renderer task; a refactor renamed or removed one of the four texture inputs; conditionally building the graph where the geometry task output handle was not yet resolved (dangling handle).","solutions":["Assign all four inputs: task.depthTexture, task.normalTexture, task.positionTexture, task.velocityTexture from the upstream geometry pass outputs before building the graph.","Confirm the upstream geometry task is added to the frame graph and its output handles are not dangling.","Order tasks so the geometry/GBUFFER task is registered before the IBL shadows renderer task.","Add a pre-build validation asserting all four properties are defined."],"exampleFix":"// before\niblShadowsRenderer.depthTexture = geometryTask.depth;\niblShadowsRenderer.normalTexture = geometryTask.normal;\n// position and velocity missing\n\n// after\niblShadowsRenderer.depthTexture = geometryTask.depth;\niblShadowsRenderer.normalTexture = geometryTask.normal;\niblShadowsRenderer.positionTexture = geometryTask.position;\niblShadowsRenderer.velocityTexture = geometryTask.velocity;","handlingStrategy":"validation","validationCode":"const missing = (['depthTexture','normalTexture','positionTexture','velocityTexture'] as const)\n    .filter(k => task[k] === undefined);\nif (missing.length) throw new Error(`IblShadowsRendererTask missing inputs: ${missing.join(', ')}`);","typeGuard":"function isIblShadowsInputReady(t: FrameGraphIblShadowsRendererTask): boolean {\n    return t.depthTexture !== undefined && t.normalTexture !== undefined && t.positionTexture !== undefined && t.velocityTexture !== undefined;\n}","tryCatchPattern":"try {\n    frameGraph.build();\n} catch (e) {\n    if (String(e).includes('depthTexture, normalTexture, positionTexture and velocityTexture are required')) {\n        console.error('Wire all 4 gbuffer outputs to the IBL shadows renderer task');\n    } else throw e;\n}","preventionTips":["Wire all four gbuffer outputs in one helper function so none can be forgotten.","Add the geometry source task before the renderer task in the graph.","Assert inputs in a unit test that builds the frame graph."],"tags":["babylonjs","frame-graph","ibl-shadows","missing-input","gbuffer"],"backgroundTag":"missing-required-input","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}