{"record":{"id":"25e900eecc377303","repo":"mrdoob/three.js","slug":"three-webglrenderer-readrendertargetpixelsasync-r-25e900","errorCode":null,"errorMessage":"THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.","messagePattern":"THREE\\.WebGLRenderer\\.readRenderTargetPixelsAsync: requested read bounds are out of range\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderers/WebGLRenderer.js","lineNumber":3254,"sourceCode":"\n\t\t\t\t\t// check if the commands have finished every 8 ms\n\t\t\t\t\tconst sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );\n\n\t\t\t\t\t_gl.flush();\n\n\t\t\t\t\tawait probeAsync( _gl, sync, 4 );\n\n\t\t\t\t\t// read the data and delete the buffer\n\t\t\t\t\t_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );\n\t\t\t\t\t_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );\n\t\t\t\t\t_gl.deleteBuffer( glBuffer );\n\t\t\t\t\t_gl.deleteSync( sync );\n\n\t\t\t\t\treturn buffer;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\t/**\n\t\t * Copies pixels from the current bound framebuffer into the given texture.\n\t\t *\n\t\t * @param {FramebufferTexture} texture - The texture.\n\t\t * @param {?Vector2} [position=null] - The start position of the copy operation.\n\t\t * @param {number} [level=0] - The mip level. The default represents the base mip.\n\t\t */\n\t\tthis.copyFramebufferToTexture = function ( texture, position = null, level = 0 ) {\n\n\t\t\tconst levelScale = Math.pow( 2, - level );\n\t\t\tconst width = Math.floor( texture.image.width * levelScale );","sourceCodeStart":3236,"sourceCodeEnd":3272,"githubUrl":"https://github.com/mrdoob/three.js/blob/da05705fa31f02710c19772a2aa70c7454807f0c/src/renderers/WebGLRenderer.js#L3236-L3272","documentation":"Thrown by readRenderTargetPixelsAsync when the requested read rectangle falls outside the render target bounds. The guard at line 3200 requires x>=0, y>=0, x <= renderTarget.width - width, and y <= renderTarget.height - height; the else branch throws.","triggerScenarios":"Passing negative x/y, a width/height larger than the target, or an x/y offset whose rectangle extends past the target's right/bottom edge. Using stale dimensions after the target was resized smaller.","commonSituations":"Reading the full target with readRenderTargetPixelsAsync(rt, 0, 0, rt.width, rt.height, buf) where buf was sized for old dimensions; computing sub-regions with inverted/clamped math; passing window pixels instead of target pixels.","solutions":["Clamp x in [0, rt.width - width] and y in [0, rt.height - height] before calling; ensure width/height <= the target's dimensions.","After resizing a render target, refresh any cached width/height used for readback and reallocate the buffer.","Validate: if (x < 0 || y < 0 || x + width > rt.width || y + height > rt.height) skip/adjust.","For full-target reads, pass exactly (0, 0, rt.width, rt.height) and a buffer of rt.width*rt.height*components."],"exampleFix":"// before\nconst buf = new Uint8Array( oldW * oldH * 4 );\nawait renderer.readRenderTargetPixelsAsync( rt, 0, 0, oldW, oldH, buf ); // throws if rt shrank\n\n// after\nconst w = rt.width, h = rt.height;\nconst buf = new Uint8Array( w * h * 4 );\nawait renderer.readRenderTargetPixelsAsync( rt, 0, 0, w, h, buf );","handlingStrategy":"validation","validationCode":"const inBounds =\n  x >= 0 && y >= 0 &&\n  x <= renderTarget.width - width &&\n  y <= renderTarget.height - height;\nif ( inBounds ) {\n  await renderer.readRenderTargetPixelsAsync( renderTarget, x, y, width, height, buf );\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp x/y and ensure width/height fit within the target dimensions.","Re-fetch rt.width/rt.height after every resize before reading.","Reallocate the readback buffer to match current target size.","Use (0,0,rt.width,rt.height) for full-target reads to avoid edge math."],"tags":["webglrenderer","readback","bounds-check","resize"],"backgroundTag":null,"analyzedSha":"da05705fa31f02710c19772a2aa70c7454807f0c","analyzedAt":"2026-08-12T22:51:37.160Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}