BabylonJS/Babylon.js · error

FrameGraphCopyToTextureTask "${this.name}": sourceTexture an

Error message

FrameGraphCopyToTextureTask "${this.name}": sourceTexture and targetTexture are required

What it means

FrameGraphCopyToTextureTask.record() requires both a sourceTexture and a targetTexture handle because it creates a copy pass between two GPU textures. If either is undefined the pass has no valid source or destination, so the task throws immediately during record.

Source

Thrown at packages/dev/core/src/FrameGraph/Tasks/Texture/copyToTextureTask.ts:54

    /**
     * Constructs a new FrameGraphCopyToTextureTask.
     * @param name The name of the task.
     * @param frameGraph The frame graph the task belongs to.
     */
    constructor(name: string, frameGraph: FrameGraph) {
        super(name, frameGraph);

        this.outputTexture = this._frameGraph.textureManager.createDanglingHandle();
    }

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

    public record() {
        if (this.sourceTexture === undefined || this.targetTexture === undefined) {
            throw new Error(`FrameGraphCopyToTextureTask "${this.name}": sourceTexture and targetTexture are required`);
        }

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

        const pass = this._frameGraph.addRenderPass(this.name);
        const passDisabled = this._frameGraph.addRenderPass(this.name + "_disabled", true);

        pass.addDependencies(this.sourceTexture);
        passDisabled.addDependencies(this.sourceTexture);

        const textureDescription = this._frameGraph.textureManager.getTextureDescription(this.targetTexture);
        const targetIsDepthTexture = IsDepthTexture(textureDescription.options.formats![0]);

        if (targetIsDepthTexture) {
            pass.setRenderTargetDepth(this.outputTexture);
            passDisabled.setRenderTargetDepth(this.outputTexture);
        } else {
            pass.setRenderTarget(this.outputTexture);

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Set both task.sourceTexture and task.targetTexture to valid frame graph texture handles before build().
  2. Verify the producing tasks are added to the graph and their outputTextures are assigned to this task's inputs.
  3. Remove the task entirely if the copy is no longer needed.

Example fix

// before
copyTask.sourceTexture = blurTask.outputTexture;
fg.addTask(copyTask);
// after
copyTask.sourceTexture = blurTask.outputTexture;
copyTask.targetTexture = fg.createTexture({ name: 'copyTarget', options: { ... } });
fg.addTask(copyTask);
Defensive patterns

Strategy: validation

Validate before calling

if (copyTask.sourceTexture === undefined || copyTask.targetTexture === undefined) {
  throw new Error('copyTask needs both sourceTexture and targetTexture before build()');
}

Type guard

function isCopyReady(t: { sourceTexture?: unknown; targetTexture?: unknown }): boolean {
  return t.sourceTexture !== undefined && t.targetTexture !== undefined;
}

Prevention

When it happens

Trigger: Adding FrameGraphCopyToTextureTask to a frame graph and calling build() with only sourceTexture set, only targetTexture set, or neither.

Common situations: Copy pipelines (e.g. for post-processing or readback) where one endpoint of the copy was not wired; a texture-producing task removed or renamed leaving a dangling undefined handle; conditional pipelines that skip creating the target texture.

Related errors


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