remotion-dev/remotion · critical · Error

Failed to create WebGL texture

Error message

Failed to create WebGL texture

What it means

Thrown inside setupNoiseDisplacement (packages/effects/src/noise-displacement.ts:495) when gl.createTexture() returns null while creating the source texture used to upload each frame for the noiseDisplacement effect. Per the WebGL spec a null texture means the context is lost, GPU memory is exhausted, or the per-context texture count is maxed out. Setup is on the first apply, so this stops the Remotion render frame.

Solutions

  1. Make sure effect cleanup runs between compositions so gl.deleteTexture reclaims textures, and cap simultaneous WebGL2 effects.
  2. Render on a GPU-equipped host (or enable WebGL in headless Chrome) so texture allocation succeeds.
  3. Handle 'webglcontextlost' on the canvas and re-render after restoration.
  4. Fall back to rendering the composition without noiseDisplacement on environments that cannot allocate the texture.

Example fix

// before
const gl = canvas.getContext('webgl2');
const tex = gl.createTexture(); // returns null -> throws

// after: detect allocation failure and degrade gracefully
const tex = gl.createTexture();
if (!tex) {
  throw new Error('noiseDisplacement unavailable on this GPU; falling back');
}
Defensive patterns

Strategy: try-catch

Validate before calling

function canAllocateNoiseDisplacementTexture(): boolean {
  try {
    const c = document.createElement('canvas');
    const gl = c.getContext('webgl2');
    if (!gl || gl.isContextLost()) return false;
    const t = gl.createTexture();
    const ok = !!t;
    if (t) gl.deleteTexture(t);
    return ok;
  } catch {
    return false;
  }
}

Try / catch

try {
  scene.push(noiseDisplacement({center: [0.5, 0.5], radius: 0.4}));
} catch (err) {
  if (/Failed to create WebGL texture/.test(String(err?.message))) {
    // fall back: omit the effect
  } else throw err;
}

Prevention

When it happens

Trigger: noiseDisplacement({...}) running when the WebGL2 context is lost or GPU memory is exhausted; many effects allocating textures concurrently past the implementation's live-texture limit; rendering very large frame sizes that exhaust texture memory.

Common situations: Long-running Studio sessions that leak textures; GPU-less headless render hosts; mobile or integrated-GPU machines with low texture memory; a GPU process crash during a render batch.

Related errors


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

Appendix: source

Thrown at packages/effects/src/noise-displacement.ts:495

	if (!vbo) {
		throw new Error('Failed to create WebGL buffer');
	}

	gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
	gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

	const aPos = gl.getAttribLocation(program, 'aPos');
	const aUv = gl.getAttribLocation(program, 'aUv');
	gl.enableVertexAttribArray(aPos);
	gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
	gl.enableVertexAttribArray(aUv);
	gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);

	gl.bindVertexArray(null);

	const texture = gl.createTexture();
	if (!texture) {
		throw new Error('Failed to create WebGL texture');
	}

	gl.bindTexture(gl.TEXTURE_2D, texture);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	gl.bindTexture(gl.TEXTURE_2D, null);

	return {
		gl,
		program,
		vao,
		vbo,
		texture,
		uniforms: {
			uSource: gl.getUniformLocation(program, 'uSource'),
			uResolution: gl.getUniformLocation(program, 'uResolution'),

View on GitHub (pinned to 78fe4bb3fd)