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

  1. Install an uncaptured error handler with device.set_uncaptured_error_handler(|err| ...) to log instead of panic.
  2. Wrap risky operations in device.push_error_scope(...)/pop_error_scope(...).await and inspect the returned error.
  3. Fix the underlying validation problem: check limits, usage flags, and bind group compatibility against device.limits()/features.
  4. In panic hooks or catching_unwind, treat this panic as fatal-by-design; wgpu errors must be handled, not caught.
  5. 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

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


AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03). Data as JSON: /api/errors/f880b308ba5eaad0. Report an issue: GitHub.