Web GPU - [Buffer (unlabeled)] used in submit while destroyed

Hello everyone,

we’ve been using Three.js in our project for about six years now. With the WebGLRenderer, everything worked fine.
Recently, however, we started migrating to WebGPURenderer because we need NodeMaterials for better integration with an external API — and that’s where the problems began.

The first issue I ran into was with the Mesh class.
When creating a mesh like this:

const mesh = new Mesh(someGeometry);

it automatically created a MeshBasicMaterial, even though Mesh was imported from three/webgpu.
Running this produced several warnings and errors in the console.
I worked around it by creating a small helper that assigns a MeshBasicNodeMaterial instead.
Still, it would be nice if Three.js automatically created a proper node material when using WebGPU.

That’s a minor issue, though.
The main problem is that my application crashes after a short time with the following warning:

[Buffer (unlabeled)] used in submit while destroyed.
While calling [Queue].Submit([[CommandBuffer from CommandEncoder “renderContext_22”]])

Question: Can someone explain what’s happening here?

I have a first hint that this might be related to calling .dispose() on some geometries.
I use .dispose() quite often to ensure GPU memory gets cleaned up properly.

At first, I thought the issue occurs when disposing a geometry that is still being used by another mesh in the scene — since this can happen in my app.
To test that theory, I built a small example where you can press “Delete” to dispose the cube’s geometry.

https://codesandbox.io/p/sandbox/magical-nobel-srg565

However, in that simplified example, the error doesn’t appear.

I’ve already implemented my own resource manager that only disposes geometries when no object in the scene is using them anymore.
Interestingly, if I remove the .dispose() calls completely, the app doesn’t crash — but of course, GPU memory (geometry and textures) keeps growing endlessly.

So I’d really like to understand what causes this error.
Maybe someone has an idea, or a minimal example where it can be reproduced, so I can narrow down the root cause.

Thanks in advance for any hints or explanations!

Hi apologies if this is coming late but if you haven’t solved this already, I think I can share something to point you in the right direction.

So from the error message it seems that the buffer is being destroyed before the engine.encodeRenderpass().submitCommand(commandBuffer) is being executed. This is the final call in webgpu to trigger a draw call to render on the target(canvas). Usually when I get this error, it is either I’m accidentally destroying a texture (assuming its a texture buffer) somewhere in my code or I’m running the render call in a loop like (requestanimation frame). So when the command encoder executes the first time, the buffer is lost after the first frame unless you include the draw call in the render loop and submit the buffer again everytime.

function animate(timestamp, reverse ) {
        if (!animationRunning) return; 
        // Calculate interpolation factor based on time
        t = (timestamp % morphDuration) / morphDuration;

        const adjustedT = reverse ? 1 - t : t; 

        // Smoothly interpolate between sphere and torus vertices
        for (let i = 0; i < currentVertices.length; i++) {
            currentVertices[i] = smoothstep(0, 1, adjustedT) * paddedTorusPositions[i] + (1 - smoothstep(0, 1, adjustedT)) * paddedSpherePositions[i];
        }
        device.queue.writeBuffer(positionsBuffer, 0, currentVertices);
    
        // Create the render pass
        const commandEncoder = device.createCommandEncoder();
        const renderPass = commandEncoder.beginRenderPass({
            colorAttachments: [{
                view: context.getCurrentTexture().createView(),
                loadOp: "clear",
                clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
                storeOp: "store"
            }],
            depthStencilAttachment: {
                view: depthStencilView, 
                depthClearValue: 1.0, 
                depthLoadOp: "clear", 
                depthStoreOp: "store", 
                stencilClearValue: 0, 
                stencilLoadOp: "clear", 
                stencilStoreOp: "store", 
            }
        });
    
        renderPass.setPipeline(renderPipeline);
        renderPass.setVertexBuffer(0, positionsBuffer);
        renderPass.setIndexBuffer(sphereIndexBuffer, "uint16");
        renderPass.setBindGroup(0, bindGroup);
        renderPass.drawIndexed(sphereIndex.length);
        renderPass.end();
    
        device.queue.submit([commandEncoder.finish()]);

        console.log("thisis time", t)
        // Stop the animation after one cycle
        if (t < 0.95) {
            requestAnimationFrame((newTimestamp) => animate(newTimestamp, reverse));
        } else{
            animationRunning = false; // Stop the animation
            console.log("Animation stopped");
        }
    }

This is a sample code from one of my recent projects, it’s written in pure webgpu/wgsl without any libraries. This is how a render pass is encoded, notice how I wrote the command encoder again and submitted with device.queue.submit([commandEncoder.finish()])and submitted within the animate function that will run every frame.

I hope this gives some direction to your problem!

Thank you for your input. Yes it seams that this is the problem but i already tried to remove geometries after some seconds if there is no reference anymore. Anyway it seams that version 0.181 has a fix due to dispose logic:

WebGPU: Fix `Renderer` not being garbage collected by shotamatsuda · Pull Request #31798 · mrdoob/three.js · GitHub.

Maybe this also fixes my problem. I will test this the next weeks.

It should be not problem to use the default materials know from WebGLRenderer in WebGPURenderer. They are compatible except for ShaderMaterial and RawShaderMaterial.

If you still experience issues with MeshBasicMaterial, please demonstrate the mentioned warnings/errors with a live example. Use the following fiddle as a starter template: three.js dev template - module - JSFiddle - Code Playground