BabylonJS/Babylon.js · error · Error

FrameGraphVolumetricLightingTask "${this.name}": lightingVol

Error message

FrameGraphVolumetricLightingTask "${this.name}": lightingVolumeMesh is empty

What it means

record() also validates that the lightingVolumeMesh input actually contains meshes. The FrameGraphMesh input exists (is not undefined) but its .meshes array is null or empty, so the task has nothing to render the lighting volume with and throws instead of recording a degenerate pass.

Source

Thrown at packages/dev/core/src/FrameGraph/Tasks/PostProcesses/volumetricLightingTask.ts:240

    public override isReady() {
        return (
            this._renderLightingVolumeMaterial.isReady() &&
            this._clearLightingVolumeTextureTask.isReady() &&
            this._renderLightingVolumeMaterial.isReady() &&
            this._blendLightingVolumeTask.isReady()
        );
    }

    public override getClassName(): string {
        return "FrameGraphVolumetricLightingTask";
    }

    public record(skipCreationOfDisabledPasses = false) {
        if (this.targetTexture === undefined || this.depthTexture === undefined || this.camera === undefined || this.lightingVolumeMesh === undefined || this.light === undefined) {
            throw new Error(`FrameGraphVolumetricLightingTask "${this.name}": targetTexture, depthTexture, camera, lightingVolumeMesh and light are required`);
        }
        if (!this.lightingVolumeMesh.meshes || this.lightingVolumeMesh.meshes.length === 0) {
            throw new Error(`FrameGraphVolumetricLightingTask "${this.name}": lightingVolumeMesh is empty`);
        }

        this._frameGraph.textureManager.resolveDanglingHandle(this.outputTexture, this.targetTexture);

        const textureManager = this._frameGraph.textureManager;

        let lightingVolumeTexture = this.lightingVolumeTexture;
        if (!lightingVolumeTexture) {
            const targetTextureCreationOptions = textureManager.getTextureCreationOptions(this.targetTexture);

            targetTextureCreationOptions.options.labels = ["InScattering"];
            targetTextureCreationOptions.options.samples = 1;

            lightingVolumeTexture = textureManager.createRenderTargetTexture(`${this.name} - lighting volume texture`, targetTextureCreationOptions);
        }

        this.lightingVolumeMesh.meshes[0].material = this._renderLightingVolumeMaterial;

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Make sure the source mesh (e.g. a bounding-box/cone mesh for the light volume) exists and is added to the mesh input before record().
  2. Check that the mesh wasn't disposed: verify mesh.isDisposed() === false and it's still in the scene.
  3. If meshes load asynchronously, wait for load completion (e.g. onReady / await) before building the frame graph.
  4. Validate input.meshes.length > 0 before calling record() and skip or error out gracefully otherwise.

Example fix

// before
const meshInput = frameGraph.createMeshInputValue([]);
task.lightingVolumeMesh = meshInput;
task.record(); // throws: lightingVolumeMesh is empty

// after
const volumeMesh = MeshBuilder.CreateBox("vol", { size: 1 }, scene);
const meshInput = frameGraph.createMeshInputValue(volumeMesh);
task.lightingVolumeMesh = meshInput;
task.record();
Defensive patterns

Strategy: validation

Validate before calling

if (!task.lightingVolumeMesh || !task.lightingVolumeMesh.meshes || task.lightingVolumeMesh.meshes.length === 0) {
    throw new Error("lightingVolumeMesh input has no meshes");
}
task.record();

Type guard

function hasMeshes(input: { meshes?: unknown[] } | undefined): input is { meshes: unknown[] } {
    return !!input && Array.isArray(input.meshes) && input.meshes.length > 0;
}

Try / catch

try {
    task.record();
} catch (e) {
    if ((e as Error).message.includes("lightingVolumeMesh is empty")) {
        console.error("Volume mesh empty or disposed; re-binding mesh input.");
        task.lightingVolumeMesh = frameGraph.createMeshInputValue(volumeMesh);
        task.record();
    } else throw e;
}

Prevention

When it happens

Trigger: Calling record() when this.lightingVolumeMesh.meshes is undefined or has length 0 — e.g. a mesh input created from an empty container, a mesh removed from the scene after the input was created, or an input handle bound to nothing.

Common situations: Passing an AssetContainer's meshes array after it was emptied/disposed; the volume mesh was disposed before frame graph build; filtering scene meshes produced an empty list; async mesh loading hadn't finished when the graph was built.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/c8c6411f119c8029. Report an issue: GitHub.