remotion-dev/remotion · error · Error
Failed to upload the 3D LUT texture
Error message
Failed to upload the 3D LUT texture (WebGL error ${uploadError}) What it means
After uploading the parsed LUT data with gl.texImage3D(..., gl.FLOAT, parsed.data), applyLut() polls gl.getError(). Any value other than gl.NO_ERROR means the GPU rejected the 3D texture upload, and the library throws with the raw WebGL error enum in the message. Unlike the size check ([25]), this catches failures at the actual upload (out-of-memory, invalid data, driver limits).
Solutions
- Decode the numeric error in the message: 0x505 (OUT_OF_MEMORY) means the LUT is too big - use a smaller LUT_3D_SIZE
- Verify the .cube data row count matches LUT_3D_SIZE^3 (a mismatched file produces INVALID_VALUE)
- Reduce LUT size (e.g. 33 -> 17) to lower memory requirements
- Check gl.isContextLost(); if lost, recreate the context and re-run setupLut
- Update GPU drivers/browser if float-texture upload fails on a known-good LUT
Example fix
// before: oversized LUT on mobile const lut = parseCubeLut(lutSize64File); applyLut(state, lut); // after: fall back to a smaller resampled LUT const lut = parseCubeLut(lutSize64File); const safe = state.gl.getParameter(state.gl.MAX_3D_TEXTURE_SIZE) < 64 ? downsampleCubeLut(lut, 32) : lut; applyLut(state, safe);
Defensive patterns
Strategy: try-catch
Validate before calling
const expected = size * size * size * 4;
if (parsed.data.length !== expected) {
throw new Error(`LUT data length ${parsed.data.length} != ${expected}`);
} Try / catch
try {
applyLut(state, content);
} catch (e) {
if (e.message.startsWith('Failed to upload the 3D LUT texture')) {
// decode WebGL error enum in message; on OUT_OF_MEMORY use a smaller LUT,
// if gl.isContextLost() recreate the context and setupLut again
}
} Prevention
- Ensure .cube data row count matches LUT_3D_SIZE^3 exactly
- Use smaller LUT sizes on memory-constrained devices
- Check context loss before uploading
- Avoid oversized 64+ LUTs on mobile; resample to 32
When it happens
Trigger: texImage3D fails with GL errors such as OUT_OF_MEMORY (LUT too large for GPU memory), INVALID_VALUE (malformed data length vs LUT_3D_SIZE^3), or driver-specific float-texture restrictions; also fires after context loss.
Common situations: Oversized LUTs on memory-constrained mobile GPUs; .cube files whose declared size doesn't match the number of data rows; browsers/GPUs with poor float (RGBA32F) texture support; context lost between texture creation and upload.
Related errors
- Failed to create LUT source texture
- Failed to create LUT texture
- Failed to create LUT vertex array
- Failed to create LUT vertex buffer
- LUT_3D_SIZE exceeds this browser's maximum 3D texture size…
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/ba5b3482932876d6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/effects/src/lut/lut-runtime.ts:202
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_3D, lutTexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
gl.texImage3D(
gl.TEXTURE_3D,
0,
gl.RGBA16F,
parsed.size,
parsed.size,
parsed.size,
0,
gl.RGBA,
gl.FLOAT,
parsed.data,
);
const uploadError = gl.getError();
if (uploadError !== gl.NO_ERROR) {
throw new Error(
`Failed to upload the 3D LUT texture (WebGL error ${uploadError})`,
);
}
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
state.cachedContent = content;
}
gl.viewport(0, 0, width, height);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipSourceY);
gl.texImage2D(
gl.TEXTURE_2D,View on GitHub (pinned to 46a3a6bf13)