mrdoob/three.js · error · Error
THREE.WebGPURenderer: ReadbackBuffer must be released before
Error message
THREE.WebGPURenderer: ReadbackBuffer must be released before being used again.
What it means
Thrown when calling readback with a ReadbackBuffer target that is still mapped (`_mapped === true`) from a previous readback. WebGL has no native mapped-buffer concept, so three emulates it; a ReadbackBuffer must be released (its 'release'/'dispose' event fired) before it can be reused for another readback. The error prevents overwriting a buffer the caller may still be consuming.
Source
Thrown at src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js:289
const { gl } = backend;
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
const attributeInfo = backend.get( bufferAttribute );
const { bufferGPU } = attributeInfo;
const byteLength = count === - 1 ? attributeInfo.byteLength - offset : count;
// read the data back
let dstBuffer;
if ( target === null ) {
dstBuffer = new Uint8Array( new ArrayBuffer( byteLength ) );
} else if ( target.isReadbackBuffer ) {
if ( target._mapped === true ) {
throw new Error( 'THREE.WebGPURenderer: ReadbackBuffer must be released before being used again.' );
}
const releaseCallback = () => {
target.buffer = null;
target._mapped = false;
target.removeEventListener( 'release', releaseCallback );
target.removeEventListener( 'dispose', releaseCallback );
};
target.addEventListener( 'release', releaseCallback );
target.addEventListener( 'dispose', releaseCallback );
// WebGL has no concept of a "mapped" data buffer so we create a new buffer, instead.
dstBuffer = new Uint8Array( new ArrayBuffer( byteLength ) );
target.buffer = dstBuffer.buffer;View on GitHub (pinned to da05705fa3)
Solutions
- Release the ReadbackBuffer after consuming its data: `readbackBuffer.release()` (or let it dispose) before reusing.
- Await the prior readback promise to completion before issuing the next one with the same target.
- Use a pool/rotation of two or more ReadbackBuffers to overlap reads instead of reusing one synchronously.
- Pass `null` as target to allocate a fresh ArrayBuffer each readback if reuse isn't required.
Example fix
// before const rb = new ReadbackBuffer(); renderer.readback(attr, 0, -1, rb); renderer.readback(attr, 0, -1, rb); // throws - still mapped // after const rb = new ReadbackBuffer(); renderer.readback(attr, 0, -1, rb); rb.release(); // unmap renderer.readback(attr, 0, -1, rb);
Defensive patterns
Strategy: validation
Validate before calling
function assertReadbackBufferFree(rb) {
if (rb && rb.isReadbackBuffer && rb._mapped === true) {
throw new Error('ReadbackBuffer is still mapped; call release() before reuse');
}
} Type guard
function readbackBufferIsFree(rb) {
return !rb || !rb.isReadbackBuffer || rb._mapped !== true;
} Try / catch
try {
renderer.readback(attr, 0, -1, rb);
} catch (e) {
if (/ReadbackBuffer must be released/.test(e.message)) { rb.release(); renderer.readback(attr, 0, -1, rb); }
else throw e;
} Prevention
- Always release a ReadbackBuffer after consuming its data.
- For per-frame readbacks, rotate between two or more buffers to avoid stalls.
- Await the previous readback before issuing the next with the same target.
When it happens
Trigger: Calling renderer.compute/com readback APIs (e.g. readbackBuffer, readback) twice in succession with the same ReadbackBuffer target without releasing it first. Holding the ReadbackBuffer across multiple frames and re-submitting it each frame without awaiting/completing the prior read.
Common situations: GPU readback loops (transform feedback, compute buffer readback) where the buffer is reused. Async readback where the caller doesn't await resolution before issuing the next readback. Forgetting to call release()/dispose() on the ReadbackBuffer after consuming its data.
Related errors
- THREE.Renderer: "getArrayBufferAsync()" offset and count mus
- THREE.WebGLTextureUtils: Unsupported WebGL type: ${glType}
- THREE.WebGLAttributes: The size of the buffer attribute's ar
- THREE.WebGPUAttributeUtils: ReadbackBuffer must be released
- THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinat
AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12).
Data as JSON: /api/errors/9264fc35f454f216.
Report an issue: GitHub.