mrdoob/three.js · error · Error
THREE.Renderer: "getArrayBufferAsync()" offset and count mus
Error message
THREE.Renderer: "getArrayBufferAsync()" offset and count must be a multiple of 4.
What it means
Thrown by Renderer.getArrayBufferAsync() when the offset or a positive count is not a multiple of 4 (bytes). GPU readback via getBufferSubData/async copies requires 4-byte alignment for the offset and length to satisfy buffer copy constraints.
Source
Thrown at src/renderers/common/Renderer.js:2125
this.info.createReadbackBuffer( target );
const disposeInfo = () => {
target.removeEventListener( 'dispose', disposeInfo );
this.info.destroyReadbackBuffer( target );
};
target.addEventListener( 'dispose', disposeInfo );
}
}
if ( offset % 4 !== 0 || ( count > 0 && count % 4 !== 0 ) ) {
throw new Error( 'THREE.Renderer: "getArrayBufferAsync()" offset and count must be a multiple of 4.' );
}
return await this.backend.getArrayBufferAsync( attribute, target, offset, count );
}
/**
* Returns the rendering context.
*
* @return {GPUCanvasContext|WebGL2RenderingContext} The rendering context.
*/
getContext() {
return this.backend.getContext();
}
View on GitHub (pinned to da05705fa3)
Solutions
- Align offset to a multiple of 4 (Math.floor(offset/4)*4) and round count up/down to a multiple of 4.
- Read whole attributes (offset 0, count -1 default) when alignment is hard to guarantee.
- Compute offset and count in terms of 4-byte units and multiply back by 4 before passing.
- If sub-range readback is essential, pad your attribute layout so sub-ranges stay 4-aligned.
Example fix
// before await renderer.getArrayBufferAsync( attribute, null, 6, 7 ); // offset 6 and count 7 not mult of 4 // after const offset = Math.floor( 6 / 4 ) * 4; // 4 const count = Math.ceil( 7 / 4 ) * 4; // 8 await renderer.getArrayBufferAsync( attribute, null, offset, count );
Defensive patterns
Strategy: validation
Validate before calling
function aligned( n ) { return Math.floor( n / 4 ) * 4; }
const safeOffset = aligned( offset );
const safeCount = count > 0 ? Math.ceil( count / 4 ) * 4 : count;
await renderer.getArrayBufferAsync( attribute, target, safeOffset, safeCount ); Prevention
- Round offset down and count up/down to a multiple of 4.
- Prefer whole-attribute reads (offset 0, count -1) when possible.
- Compute offset/count in 4-byte units and scale back by 4.
- Pad attribute layouts so sub-range reads stay 4-aligned.
When it happens
Trigger: Passing an odd offset, or a count not divisible by 4, to getArrayBufferAsync(attribute, target, offset, count). Note count <= 0 (e.g. the default -1) skips the count alignment check, so only positive counts are validated.
Common situations: Reading sub-ranges of tightly packed attribute arrays with element sizes that break 4-byte alignment; computing offset/count from element counts without accounting for byte stride; partial reads for picking/debugging.
Related errors
- THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinat
- THREE.Renderer: .compileComputeAsync() expects a ComputeNode
- THREE.Renderer: .render() called before the backend is initi
- THREE.Renderer: .compute() expects a ComputeNode.
- THREE.Renderer: .hasFeature() called before the backend is i
AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12).
Data as JSON: /api/errors/4a5750e57b4a9f04.
Report an issue: GitHub.