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

  1. 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.
  2. Check gl.isContextLost() before relying on the effect and re-run after the context is restored; Remotion's canvas pool recreates contexts on restore.
  3. Reduce the number of distinct evolve() param combinations rendered simultaneously so each GL context owns fewer linked programs.
  4. Update GPU drivers on the render host, or force a consistent software/Angle path in CI to avoid flaky driver linkers.
  5. 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

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


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/5d754951632872ff. Report an issue: GitHub.