remotion-dev/remotion · error · Error

Failed to create WebGL buffer

Error message

Failed to create WebGL buffer

What it means

Thrown during setupFisheye() when gl.createBuffer() returns null (fisheye-runtime.ts:119-122). A null VBO means the driver declined to allocate another buffer object — context lost or the buffer-object pool exhausted. The fisheye fullscreen-quad vertex data has no storage, so setup aborts.

Source

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

	gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);

	const program = createProgram(gl, FISHEYE_VS, FISHEYE_FS);

	const vao = gl.createVertexArray();
	if (!vao) {
		throw new Error('Failed to create WebGL vertex array');
	}

	gl.bindVertexArray(vao);

	const data = new Float32Array([
		-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1, 1, 1, 1, 1,
	]);

	const vbo = gl.createBuffer();
	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);

	gl.enableVertexAttribArray(0);
	gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 16, 0);
	gl.enableVertexAttribArray(1);
	gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 16, 8);

	gl.bindVertexArray(null);

	const textureSource = createRgbaTexture(gl);

	return {
		gl,
		program,
		vao,

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.deleteBuffer).
  3. Lower simultaneous WebGL2 effect count and reuse identical fisheye() params via calculateKey.
  4. Check gl.isContextLost() and restore before retrying.
  5. Use a render host with adequate GPU memory or a stable software GL path.

Example fix

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

// 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 canAllocateBuffer = (gl: WebGL2RenderingContext): boolean => {
  if (gl.isContextLost()) return false;
  const probe = gl.createBuffer();
  if (!probe) return false;
  gl.deleteBuffer(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 buffer') {
    // 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() gets past createVertexArray() but gl.createBuffer() returns null. This happens on a lost context or when leaked VBOs (from setupFisheye() without cleanupFisheye(), or many effect() instances) have exhausted the driver's buffer-object budget.

Common situations: Apps using fisheye-runtime directly without cleanupFisheye(); long-running sessions accumulating un-cleaned effect canvases; compositions rendering many WebGL2 effects at once; headless CI with constrained GL resources; contexts reported lost after a GPU crash.

Related errors


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