remotion-dev/remotion · error · Error
Failed to create levels shader
Error message
Failed to create levels shader
What it means
Thrown by `compileShader()` inside the levels effect when `gl.createShader()` returns `null`. The WebGL2 spec returns null only on context loss, an invalid enum, or resource/GPU exhaustion — the effect cannot build its shader program and bails before compiling.
Source
Thrown at packages/effects/src/levels.ts:161
vec3 normalized = clamp(
(color - vec3(uBlackPoint)) / (uWhitePoint - uBlackPoint),
0.0,
1.0
);
vec3 corrected = pow(normalized, vec3(1.0 / uGamma));
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 levels 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(`Levels 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
- Reduce the number of live WebGL2 contexts — close other Studio tabs or lower concurrency (`--concurrency`).
- Ensure the renderer has a working GPU: avoid `--disable-gpu` in headless Chrome; use a GPU-enabled Chromium or swiftshader build that still exposes WebGL2.
- Listen for `webglcontextlost` and tear down/recreate the effect, or retry the render after the context is restored.
- If running in CI/Lambda, confirm the Chrome binary and GPU flags match Remotion's supported headless setup.
Defensive patterns
Strategy: try-catch
Validate before calling
function glReady(gl: WebGL2RenderingContext | null): boolean {
if (!gl) return false;
// Probe a throwaway shader allocation cheaply.
const probe = gl.createShader(gl.VERTEX_SHADER);
if (!probe) return false;
gl.deleteShader(probe);
return gl.isContextLost() === false;
} Type guard
const hasWebGL2 = (): boolean => {
const c = document.createElement('canvas');
return !!c.getContext('webgl2');
}; Try / catch
try {
levels({...})(...);
} catch (err) {
if (/Failed to create levels shader/.test(String(err))) {
// context loss / no GPU: skip effect or schedule a retry after restore
console.warn('levels() unavailable, falling back to no-op', err);
} else {
throw err;
}
} Prevention
- Keep concurrent WebGL2 contexts well below the ~16 browser cap.
- In headless rendering, use a GPU-backed Chrome (no --disable-gpu) or a WebGL2-capable swiftshader.
- Add a `webglcontextlost` listener to tear down effects and retry on restore.
When it happens
Trigger: The WebGL2 context was lost (e.g. tab backgrounded, GPU driver reset), too many simultaneous WebGL contexts are open (browsers cap around 16), the GPU is unavailable in a headless/CI environment, or video memory is exhausted.
Common situations: Rendering many compositions concurrently on the same machine; running Remotion Lambda/headless Chrome with `--disable-gpu` or swiftshader; a long-running Studio tab that lost its context after suspend; opening dozens of effect previews at once.
Related errors
- Failed to create levels shader program
- Failed to create levels texture
- Failed to create levels vertex array
- Failed to create levels vertex buffer
- Failed to create WebGL shader
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/ecf50be7fc248ec4.
Report an issue: GitHub.