remotion-dev/remotion · error · Error

Failed to create WebGL texture

Error message

Failed to create WebGL texture

What it means

Thrown inside createRgbaTexture() in fisheye-runtime.ts when gl.createTexture() returns null (fisheye-runtime.ts:80-83). A null texture means the driver would not allocate another texture object — context lost or texture pool/GPU memory exhausted. The fisheye source sampler has no target, so setup aborts.

Source

Thrown at packages/effects/src/fisheye/fisheye-runtime.ts:82

};

const createProgram = (
	gl: WebGL2RenderingContext,
	vertexSource: string,
	fragmentSource: string,
): WebGLProgram => {
	const vs = compileShader(gl, gl.VERTEX_SHADER, vertexSource);
	const fs = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
	const program = linkProgram(gl, vs, fs);
	gl.deleteShader(vs);
	gl.deleteShader(fs);
	return program;
};

const createRgbaTexture = (gl: WebGL2RenderingContext): WebGLTexture => {
	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 texture;
};

export const setupFisheye = (target: HTMLCanvasElement): FisheyeState => {
	const gl = target.getContext('webgl2', {
		premultipliedAlpha: true,
		alpha: true,
		preserveDrawingBuffer: true,
	});
	if (!gl) {

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Render with --gl=angle (CLI) / chromiumOptions.gl='angle' (SSR) / Angle (Studio).
  2. If using fisheye-runtime directly, always pair setupFisheye() with cleanupFisheye() (it calls gl.deleteTexture).
  3. Cut the simultaneous WebGL2 effect count and reuse identical fisheye() params via calculateKey.
  4. Check gl.isContextLost() and restore the context before retrying.
  5. Move to a host with more GPU memory or a consistent software GL path.

Example fix

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

// after (cleanup discipline for direct runtime use)
const state = setupFisheye(canvas);
try { /* applyFisheye(...) */ } finally { cleanupFisheye(state); }
Defensive patterns

Strategy: try-catch

Validate before calling

const canAllocateTexture = (gl: WebGL2RenderingContext): boolean => {
  if (gl.isContextLost()) return false;
  const probe = gl.createTexture();
  if (!probe) return false;
  gl.deleteTexture(probe);
  return true;
};

Try / catch

import {setupFisheye, cleanupFisheye} from '@remotion/effects/fisheye-runtime';

let state;
try {
  state = setupFisheye(canvas);
} catch (err) {
  if (err instanceof Error && err.message === 'Failed to create WebGL texture') {
    // free other fisheye states, restore context, retry on Angle
    throw err;
  }
  throw err;
}
try { /* applyFisheye(state, ...) */ } finally { cleanupFisheye(state); }

Prevention

When it happens

Trigger: setupFisheye() calls createRgbaTexture() (the source texture used by uSource) and gl.createTexture() returns null. This occurs when the WebGL2 context is lost or when leaked textures (from setupFisheye() without cleanupFisheye(), or many effect() instances) have exhausted the driver's texture-object/memory budget.

Common situations: Apps using fisheye-runtime directly without cleanupFisheye(); long-running sessions leaking textures; compositions with many simultaneous fisheye()/WebGL2 layers; headless CI hosts with limited GPU memory; contexts left lost after a GPU crash.

Related errors


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