gfx-rs/wgpu · error
${name} is not webgpu
Error message
${name} is not webgpu What it means
This panic is emitted by wgpu's generated dispatch enum accessor `as_webgpu()` (defined by the `dispatch_types!` macro in wgpu/src/dispatch.rs:852). The dispatch enum (e.g. `DispatchBindGroup`) wraps one of several backend variants (Core, WebGPU, Custom); `as_webgpu()` returns the inner `webgpu`-backend object only if the enum actually holds the `WebGPU` variant, and panics with '<Name> is not webgpu' otherwise. It exists because wgpu compiles to multiple backends behind one opaque handle type, so unchecked backend downcasts must fail loudly.
Source
Thrown at wgpu/src/dispatch.rs:852
}
#[cfg(custom)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_custom<T: $interface>(&self) -> Option<&T> {
match self {
Self::Custom(value) => value.downcast(),
_ => None,
}
}
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu(&self) -> &$webgpu_type {
match self {
Self::WebGPU(value) => value,
_ => panic!(concat!(stringify!($name), " is not webgpu")),
}
}
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
match self {
Self::WebGPU(value) => Some(value),
_ => None,
}
}
#[cfg(custom)]
#[inline]
pub fn custom<T: $interface>(t: T) -> Self {
Self::Custom($custom_type::new(t))
}View on GitHub (pinned to 3e11ff59bf)
Solutions
- Use the non-panicking `as_webgpu_opt()` (returns Option<&WebGPUType>) and handle None instead
- Check which backend actually constructed the handle; if running natively, use `as_core()` / `as_core_opt()`
- Align cargo features so only the intended backend (wgpu_core OR webgpu) is enabled, or branch on the active feature with #[cfg]
- Call methods through the Deref target (`dyn` interface trait) instead of downcasting to a specific backend
Example fix
// before
let inner = bind_group.as_webgpu();
// after
let Some(inner) = bind_group.as_webgpu_opt() else {
// handle Core/Custom backend case
return;
}; Defensive patterns
Strategy: type-guard
Validate before calling
// Compile-time: ensure the webgpu backend is the active one #[cfg(all(webgpu, not(wgpu_core)))] const WEBGPU_ONLY: () = ();
Type guard
fn is_webgpu(h: &wgpu::DispatchBindGroup) -> bool {
h.as_webgpu_opt().is_some()
} Try / catch
// Panics are not catchable in Rust; avoid via Option accessor
match handle.as_webgpu_opt() {
Some(v) => use_webgpu(v),
None => eprintln!("handle is not webgpu-backed"),
} Prevention
- Prefer as_webgpu_opt() over as_webgpu() in application code
- Only call backend-specific accessors behind matching #[cfg] gates
- Don't mix native and WASM builds of the same code path unguarded
- Use the shared trait methods via Deref instead of backend downcasts
When it happens
Trigger: Calling `dispatch_handle.as_webgpu()` on a handle whose enum value is `Core(...)` or `Custom(...)` — e.g. building with the native `wgpu_core` feature (as the benchmark benches/benches/wgpu-benchmark/bind_groups.rs does via DeviceState) and then calling `as_webgpu()`, or holding a handle produced by a WebGPU-backend instance in a code path that assumes a Core object.
Common situations: Mixing native and WASM builds: code written for the browser (WebGPU backend) is run natively where handles are Core-backed; feature-flag mismatches (webgpu enabled alongside wgpu_core) where the code assumes the wrong variant; downstream code reaching into wgpu internals during a wgpu-internal refactor.
Related errors
- wgpu error: {err}
- Mismatched pop_error_scope call: no error scope for this thr
- Mismatched pop_error_scope call: error scopes must be popped
- Unexpected error: constructor={constructor} value={value}
- {:?} is not enabled for this backend
AI-assisted analysis of gfx-rs/wgpu@3e11ff59bf (2026-09-03).
Data as JSON: /api/errors/c1099b7ea7215229.
Report an issue: GitHub.