remotion-dev/remotion · error · Error

Failed to create WebGL shader

Error message

Failed to create WebGL shader

What it means

Thrown by the duotone effect's internal compileShader() when gl.createShader(type) returns null. The WebGL2 context was already acquired successfully (createWebGL2ContextError would have thrown earlier otherwise), so a null shader object means the driver refused to allocate one. Per the WebGL spec, createShader returns null only when the context is lost or the implementation cannot create another resource.

Source

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

		return;
	}

	vec3 rgb = texColor.rgb / alpha;
	float luminance = dot(rgb, vec3(0.299, 0.587, 0.114));
	vec3 duotoneColor = luminance < uThreshold ? uDarkColor : uLightColor;

	fragColor = vec4(duotoneColor * alpha, alpha);
}
`;

const compileShader = (
	gl: WebGL2RenderingContext,
	type: number,
	source: string,
): WebGLShader => {
	const shader = gl.createShader(type);
	if (!shader) {
		throw new Error('Failed to create WebGL shader');
	}

	gl.shaderSource(shader, source);
	gl.compileShader(shader);
	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		const log = gl.getShaderInfoLog(shader);
		gl.deleteShader(shader);
		throw new Error(`Duotone shader compile failed: ${log ?? '(no log)'}`);
	}

	return shader;
};

const linkProgram = (
	gl: WebGL2RenderingContext,
	vs: WebGLShader,
	fs: WebGLShader,
): WebGLProgram => {

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Render with a software/ANGLE WebGL backend, e.g. `npx remotion render <comp> --output out.mp4 --gl=swiftshader` (also try --gl=angle, --gl=swangle).
  2. Enable hardware acceleration in the browser used for Studio preview, or run preview on a machine with a working GPU.
  3. Lower render concurrency (--concurrency) so each frame's WebGL contexts are created and torn down without exhausting GPU resources.
  4. Update the Chromium build Remotion drives (newer builds carry GPU-process fixes); on Lambda, use a current Chrome layer.
Defensive patterns

Strategy: try-catch

Try / catch

// Resource-allocation failures are GPU-state dependent and cannot be predicted,
// so catch the render promise and retry on a different GL backend.
async function safeRender(opts) {
  try {
    return await renderMedia(opts);
  } catch (err) {
    if (/WebGL/.test(String(err?.message ?? ''))) {
      return await renderMedia({...opts, gl: 'swiftshader'});
    }
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling duotone() in a composition that is being rendered or previewed on a Chrome instance whose GPU process is unavailable, has crashed, or has exhausted its WebGL object budget. The failure occurs inside setupDuotone() during the first frame that wires up the duotone program.

Common situations: Headless/CI Chrome with no GPU access, hardware acceleration disabled in the local browser, too many simultaneous WebGL contexts (many concurrent render workers or several GPU effects on one frame), a GPU driver reset mid-render.

Related errors


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