remotion-dev/remotion · error · Error

Duotone program link failed: ${log ?? '(no log)'}

Error message

Duotone program link failed: ${log ?? '(no log)'}

What it means

Thrown by duotone's linkProgram() when gl.getProgramParameter(program, gl.LINK_STATUS) is false after both shaders compiled and the program was allocated. The program info log is embedded. With both shaders compiled from fixed library GLSL, a link failure means the driver could compile each stage but not bind them together, pointing at a driver/translation defect rather than user input.

Source

Thrown at packages/effects/src/duotone.ts:168

};

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(`Duotone program link failed: ${log ?? '(no log)'}`);
	}

	return program;
};

const createProgram = (
	gl: WebGL2RenderingContext,
	vertexSource: string,
	fragmentSource: string,
): WebGLProgram => {
	const vs = compileShader(gl, gl.VERTEX_SHADER, vertexSource);
	const fs = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
	const program = linkProgram(gl, vs, fs);
	gl.deleteShader(vs);
	gl.deleteShader(fs);
	return program;
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Change the GL backend and re-render: `npx remotion render <comp> --gl=swiftshader` (or --gl=angle).
  2. Update the GPU driver and Chromium build.
  3. If it reproduces on multiple backends, report it as a Remotion bug with the program info log from the message.
Defensive patterns

Strategy: fallback

Try / catch

async function renderWithFallback(opts) {
  try {
    return await renderMedia(opts);
  } catch (err) {
    const msg = String(err?.message ?? '');
    if (/program link failed/i.test(msg)) {
      return await renderMedia({...opts, gl: 'swiftshader'});
    }
    throw err;
  }
}

Prevention

When it happens

Trigger: First-frame setup of duotone() on a driver that compiles DUOTONE_VS and DUOTONE_FS individually but fails to link them (e.g. varying/uniform incompatibility introduced by the driver's shader translator).

Common situations: Buggy or outdated GPU drivers, ANGLE/SwiftShader regressions, or a Chromium shader-translator change that breaks linking for this effect on a specific platform.

Related errors


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