{"record":{"id":"92dbc7a08673b2ce","repo":"remotion-dev/remotion","slug":"failed-to-create-webgl-shader-92dbc7","errorCode":null,"errorMessage":"Failed to create WebGL shader","messagePattern":"Failed to create WebGL shader","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/effects/src/skew.ts","lineNumber":164,"sourceCode":"\tvec2 sourceUv = vec2(sourceX, sourceY) / uResolution + uOrigin;\n\n\tif (any(lessThan(sourceUv, vec2(0.0))) || any(greaterThan(sourceUv, vec2(1.0)))) {\n\t\tfragColor = vec4(0.0);\n\t\treturn;\n\t}\n\n\tfragColor = texture(uSource, sourceUv);\n}\n`;\n\nconst compileShader = (\n\tgl: WebGL2RenderingContext,\n\ttype: number,\n\tsource: string,\n): WebGLShader => {\n\tconst shader = gl.createShader(type);\n\tif (!shader) {\n\t\tthrow new Error('Failed to create WebGL shader');\n\t}\n\n\tgl.shaderSource(shader, source);\n\tgl.compileShader(shader);\n\tif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n\t\tconst log = gl.getShaderInfoLog(shader);\n\t\tgl.deleteShader(shader);\n\t\tthrow new Error(`Skew shader compile failed: ${log ?? '(no log)'}`);\n\t}\n\n\treturn shader;\n};\n\nconst setupSkew = (target: HTMLCanvasElement): SkewState => {\n\tconst gl = target.getContext('webgl2', {\n\t\tpremultipliedAlpha: true,\n\t\talpha: true,\n\t\tpreserveDrawingBuffer: true,","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/skew.ts#L146-L182","documentation":"The skew() effect's WebGL2 backend could not allocate a shader object: gl.createShader() returned null inside compileShader() in packages/effects/src/skew.ts. A null return means the WebGL2 context is lost, resource-exhausted, or backed by a non-conformant driver, so the library cannot compile the vertex/fragment shaders it needs and throws before setup completes. This is an environment failure, not a parameter error — the context was acquired moments earlier (otherwise createWebGL2ContextError would have fired first).","triggerScenarios":"Calling skew({...}) in a render where the WebGL2 context acquired in setupSkew() has entered a lost state, or where the process already holds too many live WebGL contexts (browsers cap active contexts, commonly ~16) so a freshly-acquired context is immediately unusable. Also reproducible under GPU memory pressure or a driver reset between getContext() and createShader().","commonSituations":"Headless Chromium rendering without --gl=angle; many parallel frames each stacking multiple WebGL2 effects; SwiftShader/llvmpipe software fallback under load; a machine whose GPU driver crashed and the context was not recovered; CI runners with no real GPU.","solutions":["Render with the ANGLE backend: add --gl=angle to the CLI, set chromiumOptions.gl='angle' in renderMediaOnLambda()/renderMedia(), or pick 'angle' in Studio Advanced > OpenGL render backend.","Lower concurrency (CLI --concurrency, or concurrency in SSR options) and/or reduce the number of WebGL2 effects stacked on a single frame so the active-context cap is not exceeded.","Make sure every effect's cleanup path runs so contexts/textures are released before new ones are allocated; avoid leaking offscreen canvases.","Verify the environment actually supports WebGL2 (driver installed, not blacklisted); update GPU drivers or run on a host with a working GPU/ANGLE setup."],"exampleFix":"// before\nawait renderMedia({ composition, serveUrl, codec: 'h264' });\n// npx remotion render main MyComp out.mp4\n\n// after\nawait renderMedia({\n  composition,\n  serveUrl,\n  codec: 'h264',\n  chromiumOptions: { gl: 'angle' },\n});\n// npx remotion render main MyComp out.mp4 --gl=angle","handlingStrategy":"try-catch","validationCode":"// Pre-flight: confirm WebGL2 is usable before relying on skew().\n// Note: this only catches 'no WebGL2 at all' — a createShader() null\n// typically means context LOSS after acquisition, which is not detectable up front.\nfunction supportsWebGL2Effect(): boolean {\n  try {\n    const c = document.createElement('canvas');\n    const gl = c.getContext('webgl2');\n    return !!gl;\n  } catch {\n    return false;\n  }\n}\nif (!supportsWebGL2Effect()) {\n  throw new Error('skew() requires WebGL2, which is unavailable in this environment');\n}","typeGuard":null,"tryCatchPattern":"try {\n  // using skew() in a render or component\n  await renderMedia({ composition, codec: 'h264', chromiumOptions: { gl: 'angle' } });\n} catch (err) {\n  if (err instanceof Error && /Failed to create WebGL shader/.test(err.message)) {\n    // context was acquired but a shader could not be allocated: treat as env failure\n    console.error('WebGL2 resource allocation failed for skew(). Retry with --gl=angle or lower concurrency.', err);\n    throw err;\n  }\n  throw err;\n}","preventionTips":["Always render WebGL2 effects with the ANGLE backend (--gl=angle / chromiumOptions.gl='angle').","Keep render concurrency and the number of stacked WebGL2 effects low enough to stay under the browser's live-context cap (~16).","Run an integration render of effects-heavy compositions in CI on a known-good GPU host before shipping.","Treat any 'Failed to create WebGL *' message as an environment problem, not a code problem — investigate drivers/GPU before the effect code."],"tags":["webgl","gpu","effects","skew","rendering","context-loss"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}