remotion-dev/remotion · critical · Error

Failed to create WebGL shader

Error message

Failed to create WebGL shader

What it means

Thrown by halftone-linear-gradient's compileShader (halftone-linear-gradient.ts:376) when gl.createShader(type) returns null. A null shader object indicates a lost WebGL2 context or GPU resource exhaustion. The library throws because subsequent gl.shaderSource would crash on null.

Source

Thrown at packages/effects/src/halftone-linear-gradient.ts:376

	uFirstStopPosition: WebGLUniformLocation | null;
	uSecondStopPosition: WebGLUniformLocation | null;
	uGridSize: WebGLUniformLocation | null;
	uColor: WebGLUniformLocation | null;
	uUseSourceColor: WebGLUniformLocation | null;
	uMaskToSourceAlpha: WebGLUniformLocation | null;
	colorCtx: CanvasRenderingContext2D;
	cachedColorStr: string;
	cachedColorRgba: ParsedColorRgba;
};

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(
			`Halftone linear gradient shader compile failed: ${log ?? '(no log)'}`,
		);
	}

	return shader;
};

const linkProgram = (
	gl: WebGL2RenderingContext,
	vs: WebGLShader,

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Register a webglcontextlost handler and rebuild effect state on webglcontextrestored.
  2. Always call cleanup() to free shaders/programs/buffers/textures.
  3. Reduce the number of live WebGL2 effects; render sequentially on constrained GPUs.
  4. Restart browser/GPU; update drivers if the failure is reproducible.

Example fix

// before: repeated setup without teardown -> eventual null allocation
useEffect(() => { halftone.setup(canvas); }, [frame]);

// after: setup once, cleanup on unmount, handle context loss
useEffect(() => {
  const canvas = ref.current!;
  const onLost = (e: Event) => e.preventDefault();
  canvas.addEventListener('webglcontextlost', onLost);
  const s = halftone.setup(canvas);
  return () => { halftone.cleanup(s); canvas.removeEventListener('webglcontextlost', onLost); };
}, []);
Defensive patterns

Strategy: try-catch

Validate before calling

const gl = canvas.getContext('webgl2');
if (!gl) throw new Error('WebGL2 unavailable');
if (gl.isContextLost()) throw new Error('WebGL2 context lost before shader allocation');

Type guard

null

Try / catch

try {
  halftoneLinearGradient.setup(canvas);
} catch (e) {
  if (e instanceof Error && e.message === 'Failed to create WebGL shader') {
    // context loss / resource exhaustion: recreate, reduce load
  }
  throw e;
}

Prevention

When it happens

Trigger: Called during the halftone effect setup (lines 442-447) for both the vertex and fragment shaders, right after acquiring the webgl2 context. Fires on context loss, on leaked shader objects, or when the driver's shader budget is exhausted.

Common situations: Long render leaking GL objects; many concurrent WebGL effects/compositions; GPU reset mid-render; constrained integrated GPUs or software renderers.

Related errors


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