gfx-rs/wgpu · critical
Could not create shader program
Error message
Could not create shader program
What it means
This panic comes from `create_srgb_present_program` in the WebGL/GLES backend when `gl.create_program()` returns a null/invalid program object. glow returns a `NativeProgram` whose truthiness reflects whether the underlying GL call succeeded, so a null result is unwrapped with `.expect(...)`. It means the WebGL context could not allocate a new program object, typically because the context is lost or the implementation limit on program objects has been reached.
Source
Thrown at wgpu-hal/src/gles/web.rs:322
0,
swapchain.extent.height as i32,
swapchain.extent.width as i32,
0,
0,
0,
swapchain.extent.width as i32,
swapchain.extent.height as i32,
glow::COLOR_BUFFER_BIT,
glow::NEAREST,
)
};
}
Ok(())
}
unsafe fn create_srgb_present_program(gl: &glow::Context) -> glow::Program {
let program = unsafe { gl.create_program() }.expect("Could not create shader program");
let vertex =
unsafe { gl.create_shader(glow::VERTEX_SHADER) }.expect("Could not create shader");
unsafe { gl.shader_source(vertex, include_str!("./shaders/srgb_present.vert")) };
unsafe { gl.compile_shader(vertex) };
let fragment =
unsafe { gl.create_shader(glow::FRAGMENT_SHADER) }.expect("Could not create shader");
unsafe { gl.shader_source(fragment, include_str!("./shaders/srgb_present.frag")) };
unsafe { gl.compile_shader(fragment) };
unsafe { gl.attach_shader(program, vertex) };
unsafe { gl.attach_shader(program, fragment) };
unsafe { gl.link_program(program) };
unsafe { gl.delete_shader(vertex) };
unsafe { gl.delete_shader(fragment) };
unsafe { gl.bind_texture(glow::TEXTURE_2D, None) };
program
}
View on GitHub (pinned to 3e11ff59bf)
Solutions
- Check for WebGL context loss (`canvas.addEventListener('webglcontextlost', ...)`) and reinitialize the wgpu device when it fires.
- Reduce the number of programs/context: reuse a single Instance/Device/Surface instead of creating new ones per component or frame.
- Verify the canvas/context is valid and not blocked: test `canvas.getContext('webgl2')` directly in the browser console and check `WEBGL_lose_context` extension state.
- Update browser/GPU drivers or force hardware acceleration on; software renderers (SwiftShader) can fail program creation under memory pressure.
Example fix
// before: panic on null program
let program = unsafe { gl.create_program() }.expect("Could not create shader program");
// after: handle creation failure gracefully
let program = unsafe { gl.create_program() }
.ok_or(crate::CreateDeviceError::OutOfMemory)?; Defensive patterns
Strategy: try-catch
Validate before calling
const gl = canvas.getContext('webgl2');
if (!gl || gl.isContextLost()) {
throw new Error('WebGL2 context unavailable or lost before creating wgpu device');
}
canvas.addEventListener('webglcontextlost', (e) => { e.preventDefault(); scheduleReinit(); }); Type guard
function hasLiveContext(gl: WebGL2RenderingContext | null): gl is WebGL2RenderingContext {
return gl !== null && !gl.isContextLost();
} Try / catch
// Rust: wrap device creation and fall back instead of panicking
match instance.request_adapter(&desc).and_then(|a| a.request_device(&dev_desc)) {
Ok(device) => start(device),
Err(e) => { log::error!("GPU init failed: {e}"); show_fallback_ui(); }
}
// JS edge: catch wasm_bindgen thrown panics around init
try { await init_wgpu(canvas); } catch (e) { showFallback('WebGL unavailable'); } Prevention
- Register webglcontextlost/webglcontextrestored listeners on the canvas before creating wgpu resources.
- Create one Instance/Device/Surface per page and reuse it; never create them per frame or per component mount.
- Check gl.isContextLost() before initializing and before any surface recreation.
- Keep GPU memory usage modest to avoid browser GPU-process OOM that triggers context loss.
When it happens
Trigger: Calling `Adapter::new` / instance initialization on the WebGL backend at the moment wgpu sets up its internal sRGB present program (`create_srgb_present_program`), when the browser's WebGL context is lost, the context is not current, or the per-context program object limit (e.g. `gl.getParameter(gl.NUM_PROGRAM_BINARY_FORMATS)`-style limits) is exhausted.
Common situations: Long-running single-page apps that leak WebGL programs/context hits until context loss; browsers throttling or killing GPU processes for background tabs; creating too many wgpu instances/devices in one page; embedding canvas in a page where WebGL was blocked or GPU blacklist forced software rendering that then failed.
Related errors
- Could not create shader
- wgpu error: {err}
- Mismatched pop_error_scope call: no error scope for this thr
- Mismatched pop_error_scope call: error scopes must be popped
- Feature `MESH_SHADING` not enabled
AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03).
Data as JSON: /api/errors/76df7d776d8b6459.
Report an issue: GitHub.