{"record":{"id":"5d754951632872ff","repo":"remotion-dev/remotion","slug":"evolve-program-link-failed-log-no-log","errorCode":null,"errorMessage":"Evolve program link failed: ${log ?? '(no log)'}","messagePattern":"Evolve program link failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/effects/src/evolve.ts","lineNumber":228,"sourceCode":"};\n\nconst linkProgram = (\n\tgl: WebGL2RenderingContext,\n\tvs: WebGLShader,\n\tfs: WebGLShader,\n): WebGLProgram => {\n\tconst program = gl.createProgram();\n\tif (!program) {\n\t\tthrow new Error('Failed to create WebGL program');\n\t}\n\n\tgl.attachShader(program, vs);\n\tgl.attachShader(program, fs);\n\tgl.linkProgram(program);\n\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\tconst log = gl.getProgramInfoLog(program);\n\t\tgl.deleteProgram(program);\n\t\tthrow new Error(`Evolve program link failed: ${log ?? '(no log)'}`);\n\t}\n\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;","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/remotion-dev/remotion/blob/78fe4bb3fdb5a2cd68724393d63cb223db333fa7/packages/effects/src/evolve.ts#L210-L246","documentation":"Thrown by the evolve effect's linkProgram() helper after gl.linkProgram() reports LINK_STATUS === false during setupEvolve(). It means both shaders compiled but the GL driver refused to link them into a usable WebGLProgram; the InfoLog is included to pinpoint the mismatch. The partially-built program is deleted before the throw, so setup cannot continue.","triggerScenarios":"Calling the evolve() effect for the first time on a param combination (calculateKey) whose setup path hits gl.getProgramParameter(program, gl.LINK_STATUS) === false. Because EVOLVE_VS/EVOLVE_FS are fixed GLSL ES 3.00 strings, this only fires on drivers whose linker rejects them or when the GL context is in a degraded/context-lost state where the shader service misbehaves.","commonSituations":"Rendering on headless Chromium with software GL (SwiftShader) or --disable-gpu where the Angle translator's linker is buggy; a GPU process crash leaving the WebGL2 context lost but not yet restored; outdated GPU drivers on the render host; too many concurrent evolve canvases stressing one GL context.","solutions":["Render with the Angle backend: pass --gl=angle to the CLI, set chromiumOptions: { gl: 'angle' } on SSR APIs, or set 'OpenGL render backend' to 'angle' in Studio's Advanced section.","Check gl.isContextLost() before relying on the effect and re-run after the context is restored; Remotion's canvas pool recreates contexts on restore.","Reduce the number of distinct evolve() param combinations rendered simultaneously so each GL context owns fewer linked programs.","Update GPU drivers on the render host, or force a consistent software/Angle path in CI to avoid flaky driver linkers.","If the InfoLog names a specific varying/uniform mismatch, verify EVOLVE_VS/EVOLVE_FS in packages/effects/src/evolve.ts were not locally modified."],"exampleFix":"// before\nconst program = linkProgram(gl, vs, fs); // throws if driver linker rejects EVOLVE shaders\n\n// after (caller-side guard for the effect pipeline)\nimport {evolve} from '@remotion/effects';\n// angle backend prevents the vast majority of link failures:\n// CLI:  remotion render <comp> --gl=angle\n// SSR:  renderMediaOnLambda({ chromiumOptions: { gl: 'angle' } })","handlingStrategy":"try-catch","validationCode":"// Before applying evolve(), confirm the GL context used by the effect is healthy.\n// (Inside Remotion's effect pipeline you do not own the canvas directly; this\n// check applies when you drive setupEvolve / a custom canvas yourself.)\nconst isHealthy = (gl: WebGL2RenderingContext): boolean =>\n  !gl.isContextLost() &&\n  typeof gl.createProgram === 'function';\n\n// In Remotion's pipeline, prefer the validated Angle path instead:\n// CLI:   remotion render <comp> --gl=angle\n// SSR:   renderMedia({ chromiumOptions: { gl: 'angle' } })\n// Studio: Advanced > OpenGL render backend = angle","typeGuard":null,"tryCatchPattern":"import {evolve} from '@remotion/effects';\n\ntry {\n  // evolve() is applied declaratively on a component; wrap any code that\n  // drives a custom evolve canvas, or guard render orchestration:\n  await renderMedia({\n    composition,\n    serveUrl,\n    chromiumOptions: { gl: 'angle' }, // primary defense against link failures\n  });\n} catch (err) {\n  if (err instanceof Error && /Evolve program link failed/.test(err.message)) {\n    // log the InfoLog, retry once on Angle, or fall back to no-effect render\n    console.error('evolve link failed; driver InfoLog:', err.message);\n    throw err;\n  }\n  throw err;\n}","preventionTips":["Render with the Angle backend everywhere (CLI --gl=angle, SSR chromiumOptions.gl='angle', Studio OpenGL=angle).","Keep the simultaneous count of WebGL2 effects low; reuse identical evolve() params so calculateKey collapses setups.","Ensure Remotion's effect lifecycle calls cleanup() so GL objects are freed between renders.","Update GPU drivers on render hosts and pin a stable GL path in CI."],"tags":["webgl","shader","glsl","linker","gpu","evolve","setup"],"backgroundTag":null,"analyzedSha":"78fe4bb3fdb5a2cd68724393d63cb223db333fa7","analyzedAt":"2026-08-12T17:18:50.444Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}