gfx-rs/wgpu · critical
wgpu error: {err}
Error message
wgpu error: {err}
What it means
This is wgpu's default global error handler. When a WebGPU validation or out-of-memory error occurs and the application has not installed its own error handler via `Device::set_uncaptured_error_handler`, wgpu logs the error and panics with 'wgpu error: {err}'. It means a wgpu API call failed validation (or the device errored) and the error was not captured by any error scope.
Source
Thrown at wgpu-core/src/error.rs:193
} else {
// direct call preserves #[track_caller] where dyn can't
default_error_handler(err)
}
}
}
}
}
impl fmt::Debug for InternalErrorSink {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ErrorSink")
}
}
#[track_caller]
fn default_error_handler(err: Error) -> ! {
log::error!("Handling wgpu errors as fatal by default");
panic!("wgpu error: {err}\n");
}
#[derive(Debug, Error)]
#[error("Error scope stack is empty")]
pub struct EmptyErrorScopeStack;
impl Device {
pub fn on_uncaptured_error(&self, handler: Arc<dyn UncapturedErrorHandler>) {
let mut error_sink = self.error_sink.0.lock();
error_sink.uncaptured_handler = Some(handler);
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-pusherrorscope>
pub fn push_error_scope(&self, filter: ErrorFilter) {
let mut error_sink = self.error_sink.0.lock();
let thread_id = thread_id::ThreadId::current();
let scopes = error_sink.scopes.entry(thread_id).or_default();
scopes.push(ErrorScope {View on GitHub (pinned to 3e11ff59bf)
Solutions
- Install an uncaptured error handler with device.set_uncaptured_error_handler(|err| ...) to log instead of panic.
- Wrap risky operations in device.push_error_scope(...)/pop_error_scope(...).await and inspect the returned error.
- Fix the underlying validation problem: check limits, usage flags, and bind group compatibility against device.limits()/features.
- In panic hooks or catching_unwind, treat this panic as fatal-by-design; wgpu errors must be handled, not caught.
- Read the full panic message: the inner Error (e.g. CreateBufferError) names the exact violated rule.
Example fix
// before
let buf = device.create_buffer(&desc); // panics on validation failure
// after
device.set_uncaptured_error_handler(|err| log::error!("wgpu error: {err}"));
let buf = device.create_buffer(&desc); Defensive patterns
Strategy: try-catch
Validate before calling
let handler = device.poll(...); // ensure device limits checked before resource creation
if desc.size > device.limits().max_buffer_size {
return Err("buffer too large");
} Try / catch
device.set_uncaptured_error_handler(|err| {
log::error!("wgpu error: {err}");
// route to telemetry instead of panicking
}); Prevention
- Always install set_uncaptured_error_handler early in app startup.
- Use push_error_scope/pop_error_scope around batched risky operations.
- Check device.limits() and device.features() before creating resources.
- Log the inner error type (CreateBufferError etc.) to pinpoint the violated rule.
When it happens
Trigger: Any wgpu call that produces a device error without an enclosing push_error_scope/pop_error_scope and without a custom uncaptured-error handler: e.g. creating a buffer larger than device limits, using a texture with wrong usage flags, submitting a command encoder with invalid passes, mapping a buffer twice, or device loss.
Common situations: Early development when resource limits (max_buffer_size, max_texture_dimension) are exceeded; forgetting push_error_scope around risky calls; running code on a device that was lost; API misuse that validation rejects (bad bind group layout matches).
Related errors
- Mismatched pop_error_scope call: no error scope for this thr
- Mismatched pop_error_scope call: error scopes must be popped
- Mismatched pop_error_scope call: error scopes must be popped
- ${name} is not webgpu
- No context available. You need to enable one of wgpu's backe
AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03).
Data as JSON: /api/errors/f880b308ba5eaad0.
Report an issue: GitHub.