remotion-dev/remotion · error · Error

Failed to create exposure shader

Error message

Failed to create exposure shader

What it means

Thrown inside compileShader() in exposure.ts when gl.createShader(type) returns null (exposure.ts:114-116). A null shader object means the GL driver would not allocate a shader handle — almost always a lost context or an exhausted shader-object pool. Without a shader handle, neither the vertex nor fragment stage can be built, so exposure setup aborts.

Source

Thrown at packages/effects/src/exposure.ts:115

	}

	vec3 unpremultiplied = sourceColor.rgb / alpha;
	vec3 linear = srgbToLinear(unpremultiplied);
	vec3 exposed = linear * exp2(uStops);
	vec3 corrected = linearToSrgb(exposed);

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

const compileShader = (
	gl: WebGL2RenderingContext,
	type: number,
	source: string,
): WebGLShader => {
	const shader = gl.createShader(type);
	if (!shader) {
		throw new Error('Failed to create exposure 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(`Exposure shader compile failed: ${log ?? '(no log)'}`);
	}

	return shader;
};

const createProgram = (gl: WebGL2RenderingContext): WebGLProgram => {
	const vertexShader = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
	const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
	const program = gl.createProgram();
	if (!program) {

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Render with the Angle backend (--gl=angle CLI / chromiumOptions.gl='angle' SSR / Angle in Studio) for stable shader allocation.
  2. Ensure effect cleanup() runs (it deletes the program and its shaders transitively); don't hold stale exposure states.
  3. Reduce simultaneous WebGL2 effects and reuse identical exposure() params so calculateKey collapses setups.
  4. Check gl.isContextLost() and restore the context before retrying the render.
  5. Update GPU drivers or move to a host with adequate GL resources.

Example fix

// before
const shader = gl.createShader(type);
if (!shader) {
  throw new Error('Failed to create exposure shader');
}

// after (caller guard)
if (gl.isContextLost()) {
  // skip exposure setup until webglcontextrestored
}
Defensive patterns

Strategy: try-catch

Validate before calling

const canAllocateShader = (gl: WebGL2RenderingContext): boolean => {
  if (gl.isContextLost()) return false;
  const probe = gl.createShader(gl.VERTEX_SHADER);
  if (!probe) return false;
  gl.deleteShader(probe);
  return true;
};

Try / catch

try {
  // apply exposure(); for a custom canvas: const state = setupExposure(canvas);
} catch (err) {
  if (err instanceof Error && err.message === 'Failed to create exposure shader') {
    // context likely lost or shader pool exhausted: free effects, retry on Angle
    throw err;
  }
  throw err;
}

Prevention

When it happens

Trigger: setupExposure() -> createProgram() -> compileShader() runs while the WebGL2 context is lost (createShader must return null per spec) or after the driver's shader-object limit is reached. Because VERTEX_SHADER/FRAGMENT_SHADER are fixed strings, source content is not the cause here — allocation is.

Common situations: Rendering on a host where the GPU process crashed and the context is lost; long-running Studio with leaked shader objects from un-cleaned effect canvases; CI with software GL and a low shader-object ceiling; many concurrent exposure() instances.

Related errors


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