gfx-rs/wgpu · critical
Could not create shader
Error message
Could not create shader
What it means
This panic fires in `create_srgb_present_program` when `gl.create_shader(glow::VERTEX_SHADER)` returns a null shader object while building the internal sRGB-present vertex shader on the WebGL/GLES backend. A null shader means the WebGL implementation refused to allocate a shader object, almost always due to context loss or exceeding the shader object limit. The panic aborts instance/device creation.
Source
Thrown at wgpu-hal/src/gles/web.rs:324
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
}
pub fn supports_srgb(&self) -> bool {
// present.frag takes care of handling srgb conversionView on GitHub (pinned to 3e11ff59bf)
Solutions
- Listen for `webglcontextlost` (call `event.preventDefault()`) and fully re-create the wgpu Instance/Device/Surface after `webglcontextrestored`.
- Cut down context and shader object count: share one device across the app and destroy unused surfaces.
- Confirm the context is healthy before creating wgpu: `canvas.getContext('webgl2')` plus `gl.isContextLost()` check.
- Test on a different browser/driver to rule out GPU-driver-specific allocation failure; enable hardware acceleration.
Example fix
// before
let vertex = unsafe { gl.create_shader(glow::VERTEX_SHADER) }.expect("Could not create shader");
// after
let vertex = unsafe { gl.create_shader(glow::VERTEX_SHADER) }
.ok_or(crate::CreateDeviceError::ResourceCreationFailed)?; Defensive patterns
Strategy: try-catch
Validate before calling
const gl = canvas.getContext('webgl2');
if (!gl) throw new Error('WebGL2 unsupported');
if (gl.isContextLost()) throw new Error('WebGL2 context lost');
// sanity: shader object creation works
const probe = gl.createShader(gl.VERTEX_SHADER);
if (!probe) throw new Error('Cannot allocate shader objects');
gl.deleteShader(probe); Type guard
function contextCanAllocateShaders(gl: WebGL2RenderingContext | null): gl is WebGL2RenderingContext {
if (!gl || gl.isContextLost()) return false;
const s = gl.createShader(gl.VERTEX_SHADER);
if (!s) return false;
gl.deleteShader(s);
return true;
} Try / catch
try {
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
device.lost.then(info => { if (info.reason !== 'destroyed') reinitWgpu(); });
} catch (e) {
renderStaticFallback();
} Prevention
- Track device.lost (WebGPU) and webglcontextlost (WebGL) and rebuild the whole pipeline on loss.
- Avoid hammering instance creation in retry loops without backoff; repeated failed creations worsen resource exhaustion.
- Test in headless/SwiftShader environments early since they have tighter resource budgets.
- Destroy unused surfaces/textures so shader and program object budgets stay free.
When it happens
Trigger: wgpu instance/device initialization on the web backend, specifically the first `gl.create_shader(VERTEX_SHADER)` call inside `create_srgb_present_program`, when the WebGL context has been lost, the context is no longer current, or the driver/browser cannot allocate more shader objects.
Common situations: Pages that accumulate many contexts (each canvas/context has its own object budget); webglcontextlost fired by browser GPU-process reset; running inside iframes or headless browsers where WebGL fallback to SwiftShader runs out of resources; hidden-tab throttling leading to context loss between frames.
Related errors
- Could not create shader program
- 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/594dbde27132a265.
Report an issue: GitHub.