{"record":{"id":"7f6e33d066327f8d","repo":"remotion-dev/remotion","slug":"failed-to-create-webgl-texture-7f6e33","errorCode":null,"errorMessage":"Failed to create WebGL texture","messagePattern":"Failed to create WebGL texture","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/effects/src/fisheye/fisheye-runtime.ts","lineNumber":82,"sourceCode":"};\n\nconst createProgram = (\n\tgl: WebGL2RenderingContext,\n\tvertexSource: string,\n\tfragmentSource: string,\n): WebGLProgram => {\n\tconst vs = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n\tconst fs = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n\tconst program = linkProgram(gl, vs, fs);\n\tgl.deleteShader(vs);\n\tgl.deleteShader(fs);\n\treturn program;\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 setupFisheye = (target: HTMLCanvasElement): FisheyeState => {\n\tconst gl = target.getContext('webgl2', {\n\t\tpremultipliedAlpha: true,\n\t\talpha: true,\n\t\tpreserveDrawingBuffer: true,\n\t});\n\tif (!gl) {","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/fisheye/fisheye-runtime.ts#L64-L100","documentation":"Thrown inside createRgbaTexture() in fisheye-runtime.ts when gl.createTexture() returns null (fisheye-runtime.ts:80-83). A null texture means the driver would not allocate another texture object — context lost or texture pool/GPU memory exhausted. The fisheye source sampler has no target, so setup aborts.","triggerScenarios":"setupFisheye() calls createRgbaTexture() (the source texture used by uSource) and gl.createTexture() returns null. This occurs when the WebGL2 context is lost or when leaked textures (from setupFisheye() without cleanupFisheye(), or many effect() instances) have exhausted the driver's texture-object/memory budget.","commonSituations":"Apps using fisheye-runtime directly without cleanupFisheye(); long-running sessions leaking textures; compositions with many simultaneous fisheye()/WebGL2 layers; headless CI hosts with limited GPU memory; contexts left lost after a GPU crash.","solutions":["Render with --gl=angle (CLI) / chromiumOptions.gl='angle' (SSR) / Angle (Studio).","If using fisheye-runtime directly, always pair setupFisheye() with cleanupFisheye() (it calls gl.deleteTexture).","Cut the simultaneous WebGL2 effect count and reuse identical fisheye() params via calculateKey.","Check gl.isContextLost() and restore the context before retrying.","Move to a host with more GPU memory or a consistent software GL path."],"exampleFix":"// before\nconst texture = gl.createTexture();\nif (!texture) {\n  throw new Error('Failed to create WebGL texture');\n}\n\n// after (cleanup discipline for direct runtime use)\nconst state = setupFisheye(canvas);\ntry { /* applyFisheye(...) */ } finally { cleanupFisheye(state); }","handlingStrategy":"try-catch","validationCode":"const canAllocateTexture = (gl: WebGL2RenderingContext): boolean => {\n  if (gl.isContextLost()) return false;\n  const probe = gl.createTexture();\n  if (!probe) return false;\n  gl.deleteTexture(probe);\n  return true;\n};","typeGuard":null,"tryCatchPattern":"import {setupFisheye, cleanupFisheye} from '@remotion/effects/fisheye-runtime';\n\nlet state;\ntry {\n  state = setupFisheye(canvas);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Failed to create WebGL texture') {\n    // free other fisheye states, restore context, retry on Angle\n    throw err;\n  }\n  throw err;\n}\ntry { /* applyFisheye(state, ...) */ } finally { cleanupFisheye(state); }","preventionTips":["When using fisheye-runtime directly, always pair setupFisheye() with cleanupFisheye() (gl.deleteTexture).","Render with Angle (--gl=angle / chromiumOptions.gl='angle').","Limit simultaneous WebGL2 effects; reuse identical fisheye() params via calculateKey.","Handle webglcontextlost and restore before retrying."],"tags":["webgl","texture","resource-allocation","gpu","fisheye","setup"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}