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

  1. Use the non-panicking `as_webgpu_opt()` (returns Option<&WebGPUType>) and handle None instead
  2. Check which backend actually constructed the handle; if running natively, use `as_core()` / `as_core_opt()`
  3. Align cargo features so only the intended backend (wgpu_core OR webgpu) is enabled, or branch on the active feature with #[cfg]
  4. 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

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


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