{"record":{"id":"a7d340468d58a98c","repo":"remotion-dev/remotion","slug":"failed-to-create-webgl-texture-a7d340","errorCode":null,"errorMessage":"Failed to create WebGL texture","messagePattern":"Failed to create WebGL texture","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/effects/src/wave/wave-runtime.ts","lineNumber":93,"sourceCode":"\treturn program;\n};\n\nconst getWaveUniforms = (\n\tgl: WebGL2RenderingContext,\n\tprogram: WebGLProgram,\n): WaveState['uniforms'] => ({\n\tuSource: gl.getUniformLocation(program, 'uSource'),\n\tuResolution: gl.getUniformLocation(program, 'uResolution'),\n\tuAmplitude: gl.getUniformLocation(program, 'uAmplitude'),\n\tuWavelength: gl.getUniformLocation(program, 'uWavelength'),\n\tuPhase: gl.getUniformLocation(program, 'uPhase'),\n\tuDirection: gl.getUniformLocation(program, 'uDirection'),\n});\n\nconst createRgbaTexture = (gl: WebGL2RenderingContext): WebGLTexture => {\n\tconst texture = gl.createTexture();\n\tif (!texture) {\n\t\tthrow new Error('Failed to create WebGL texture');\n\t}\n\n\tgl.bindTexture(gl.TEXTURE_2D, texture);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.bindTexture(gl.TEXTURE_2D, null);\n\treturn texture;\n};\n\nexport const setupWave = (target: HTMLCanvasElement): WaveState => {\n\tconst gl = target.getContext('webgl2', {\n\t\tpremultipliedAlpha: true,\n\t\talpha: true,\n\t\tpreserveDrawingBuffer: true,\n\t});\n\tif (!gl) {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/wave/wave-runtime.ts#L75-L111","documentation":"Thrown by createRgbaTexture() when gl.createTexture() returns null. WebGL's createTexture returns null only when the context is lost, the context has been destroyed, or the implementation has exhausted its texture object pool. This is a GPU resource allocation failure, not a param validation issue.","triggerScenarios":"Called from setupWave() at packages/effects/src/wave/wave-runtime.ts:146 via createRgbaTexture(gl). Fires when the WebGL2 context on the target canvas is lost or when too many textures are already allocated without being deleted. The effect framework manages texture lifecycle, so this points to either context loss or a leak.","commonSituations":"Long-running Remotion Studio sessions that create and destroy many effects without proper cleanup (memory leak in custom effect wrappers); rendering a very long video with many scene changes that each create WebGL contexts; the browser tab's GPU process crashed and the context is in a lost state; testing in an environment with very limited GPU memory.","solutions":["Ensure every effect canvas is properly cleaned up — call cleanupWave(state) (or let the effect framework handle cleanup) before creating a new one.","Check for a 'webglcontextlost' event listener on your canvas; if the context was lost, discard it and create a new canvas before retrying.","Reduce the number of simultaneous effects or scene complexity to lower GPU memory pressure.","Restart the browser / render worker to release leaked GPU resources if this appears after long sessions.","In Remotion Lambda or headless rendering, ensure the render worker process is recycled between heavy jobs."],"exampleFix":"// before\nconst state = setupWave(canvas);\n// ... many frames later, creating another wave without cleanup\nconst state2 = setupWave(anotherCanvas); // texture pool exhausted\n\n// after: clean up previous state before allocating new resources\ncleanupWave(state);\nconst state2 = setupWave(anotherCanvas);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Check context health before setup, and catch allocation failures.\nconst gl = canvas.getContext('webgl2');\nif (!gl || gl.isContextLost()) {\n  // do not attempt setupWave on a lost context\n  return;\n}\ntry {\n  const state = setupWave(canvas);\n} catch (e) {\n  if ((e as Error).message === 'Failed to create WebGL texture') {\n    // resource exhaustion or context loss — recreate canvas\n    console.warn('Wave texture allocation failed:', (e as Error).message);\n  }\n}","preventionTips":["Always call cleanupWave(state) before discarding an effect instance.","Listen for 'webglcontextlost' and prevent default to allow restoration.","Avoid creating many concurrent effect canvases in a single composition."],"tags":["webgl","gpu","texture","resource-exhaustion","wave-effect"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}