remotion-dev/remotion · error · Error
Evolve program link failed: ${log ?? '(no log)'}
Error message
Evolve program link failed: ${log ?? '(no log)'} What it means
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.
Source
Thrown at packages/effects/src/evolve.ts:228
};
const linkProgram = (
gl: WebGL2RenderingContext,
vs: WebGLShader,
fs: WebGLShader,
): WebGLProgram => {
const program = gl.createProgram();
if (!program) {
throw new Error('Failed to create WebGL program');
}
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
const log = gl.getProgramInfoLog(program);
gl.deleteProgram(program);
throw new Error(`Evolve program link failed: ${log ?? '(no log)'}`);
}
return program;
};
const createRgbaTexture = (gl: WebGL2RenderingContext): WebGLTexture => {
const texture = gl.createTexture();
if (!texture) {
throw new Error('Failed to create WebGL texture');
}
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;View on GitHub (pinned to 78fe4bb3fd)
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.
Example fix
// before
const program = linkProgram(gl, vs, fs); // throws if driver linker rejects EVOLVE shaders
// after (caller-side guard for the effect pipeline)
import {evolve} from '@remotion/effects';
// angle backend prevents the vast majority of link failures:
// CLI: remotion render <comp> --gl=angle
// SSR: renderMediaOnLambda({ chromiumOptions: { gl: 'angle' } }) Defensive patterns
Strategy: try-catch
Validate before calling
// Before applying evolve(), confirm the GL context used by the effect is healthy.
// (Inside Remotion's effect pipeline you do not own the canvas directly; this
// check applies when you drive setupEvolve / a custom canvas yourself.)
const isHealthy = (gl: WebGL2RenderingContext): boolean =>
!gl.isContextLost() &&
typeof gl.createProgram === 'function';
// In Remotion's pipeline, prefer the validated Angle path instead:
// CLI: remotion render <comp> --gl=angle
// SSR: renderMedia({ chromiumOptions: { gl: 'angle' } })
// Studio: Advanced > OpenGL render backend = angle Try / catch
import {evolve} from '@remotion/effects';
try {
// evolve() is applied declaratively on a component; wrap any code that
// drives a custom evolve canvas, or guard render orchestration:
await renderMedia({
composition,
serveUrl,
chromiumOptions: { gl: 'angle' }, // primary defense against link failures
});
} catch (err) {
if (err instanceof Error && /Evolve program link failed/.test(err.message)) {
// log the InfoLog, retry once on Angle, or fall back to no-effect render
console.error('evolve link failed; driver InfoLog:', err.message);
throw err;
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Exposure shader link failed: ${log ?? '(no log)'}
- Program link failed: ${log ?? '(no log)'}
- Exposure shader compile failed: ${log ?? '(no log)'}
- Shader compile failed: ${log ?? '(no log)'}
- Linear gradient program link failed: ${log ?? '(no log)'}
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/5d754951632872ff.
Report an issue: GitHub.