BabylonJS/Babylon.js · critical · Error

Unable to create program

Error message

Unable to create program

What it means

_createShaderProgram calls context.createProgram(); if the WebGL context returns null the engine throws "Unable to create program". Null from createProgram means the driver could not allocate a program object — typically a lost context or GPU resource exhaustion.

Source

Thrown at packages/dev/core/src/Engines/thinEngine.functions.ts:174

    return pipelineContext;
}

/**
 * @internal
 */
export function _createShaderProgram(
    pipelineContext: WebGLPipelineContext,
    vertexShader: WebGLShader,
    fragmentShader: WebGLShader,
    context: WebGLContext,
    _transformFeedbackVaryings: Nullable<string[]> = null,
    validateShaderPrograms?: boolean
): WebGLProgram {
    const shaderProgram = context.createProgram();
    pipelineContext.program = shaderProgram;

    if (!shaderProgram) {
        throw new Error("Unable to create program");
    }

    context.attachShader(shaderProgram, vertexShader);
    context.attachShader(shaderProgram, fragmentShader);

    context.linkProgram(shaderProgram);

    pipelineContext.context = context;
    pipelineContext.vertexShader = vertexShader;
    pipelineContext.fragmentShader = fragmentShader;

    if (!pipelineContext.isParallelCompiled) {
        _finalizePipelineContext(pipelineContext, context, validateShaderPrograms);
    }

    return shaderProgram;
}

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Check gl.isContextLost(); if lost, wait for webglcontextrestored and rebuild the engine/effect cache.
  2. Reduce shader program count: merge effects, reuse materials, and dispose unused effects.
  3. Retry effect creation after resources are released.
  4. Catch the error at the scene/effect level and fall back to a simpler material.

Example fix

// before
const effect = new Effect(shaderName, attrs, uniforms, engine);
// after
try {
  const effect = new Effect(shaderName, attrs, uniforms, engine);
} catch (e) {
  if (/Unable to create program/.test(e.message) && engine._gl.isContextLost()) {
    await contextRestoredPromise;
    effect = new Effect(shaderName, attrs, uniforms, engine);
  }
}
Defensive patterns

Strategy: retry

Validate before calling

if (engine._gl.isContextLost()) {
  await new Promise(r => engine._gl.getExtension('') ?? r); // or listen for webglcontextrestored first
}

Type guard

function isEngineContextAlive(engine) {
  const gl = (engine as any)._gl;
  return !!gl && !gl.isContextLost();
}

Try / catch

try {
  effect = new Effect(name, attrs, uniforms, engine);
} catch (e) {
  if (/Unable to create program/.test(e.message)) {
    await contextRestored(engine);
    effect = new Effect(name, attrs, uniforms, engine);
  }
}

Prevention

When it happens

Trigger: Compiling/linking a shader effect when gl.createProgram() returns null: context lost after device removal, too many live programs, or driver OOM.

Common situations: Tab backgrounded/GPU process crashed during effect compilation, mobile device under memory pressure with hundreds of unique shaders, context restored without rebuilding engine state.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/fcb26412e9006a35. Report an issue: GitHub.