gfx-rs/wgpu · critical

Accessing the GPU is only supported on the main thread or…

Error message

Accessing the GPU is only supported on the main thread or from a dedicated worker

What it means

ContextWebGpu::new panics when navigator.gpu (or the worker-equivalent) cannot be retrieved via get_browser_gpu_property. WebGPU is only accessible on the main thread or inside a dedicated Web Worker; shared workers, service workers, and non-browser environments have no GPU object. wgpu panics at instance creation because the whole backend is unusable without it.

Solutions

  1. Create the wgpu Instance on the main thread or in a DedicatedWorker and pass resources/handles as needed.
  2. Check 'gpu' in navigator (and window.isSecureContext) before instantiating and fall back to another backend or show a support message.
  3. Serve the app over HTTPS/localhost and use a browser with WebGPU enabled (Chrome 113+, Edge, recent Firefox/Safari).

Example fix

// before
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default()); // panics in service worker
// after (main thread)
if (!("gpu" in navigator) || !window.isSecureContext) { throw new Error("WebGPU unavailable"); }
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
Defensive patterns

Strategy: validation

Validate before calling

// run before creating an Instance on web
if js_sys::Reflect::get(&web_sys::window().unwrap().navigator(), &"gpu".into()).is_err() || !js_sys::eval("window.isSecureContext").unwrap().is_truthy() {
    panic!("WebGPU unavailable: need main thread or dedicated worker, secure context, WebGPU-capable browser");
}

Type guard

fn webgpu_available(navigator: &web_sys::Navigator) -> bool {
    js_sys::Reflect::has(navigator.as_ref(), &"gpu".into()).unwrap_or(false)
}

Prevention

When it happens

Trigger: Calling wgpu::Instance::new (or creating a ContextWebGpu) from a shared worker or service worker, from a thread without navigator.gpu, or in an environment where navigator.gpu is undefined (no WebGPU support / insecure context).

Common situations: Running WASM code inside a Service Worker (e.g. offline processing); older browsers without WebGPU; serving over plain HTTP instead of HTTPS (WebGPU requires a secure context); creating the instance on a spawned non-dedicated worker thread.

Related errors


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

Appendix: source

Thrown at wgpu/src/backend/webgpu.rs:1651

crate::cmp::impl_eq_ord_hash_proxy!(WebPipelineCache => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebCommandEncoder => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebComputePassEncoder => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebRenderPassEncoder => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebCommandBuffer => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebRenderBundleEncoder => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebRenderBundle => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebSurface => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebSurfaceOutputDetail => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebQueueWriteBuffer => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebBufferMappedRange => .ident);

impl dispatch::InstanceInterface for ContextWebGpu {
    fn new(desc: crate::InstanceDescriptor) -> Self
    where
        Self: Sized,
    {
        let Ok(gpu) = get_browser_gpu_property() else {
            panic!(
                "Accessing the GPU is only supported on the main thread or from a dedicated worker"
            );
        };

        ContextWebGpu {
            gpu,
            requested_backends: desc.backends,
            ident: crate::cmp::Identifier::create(),
        }
    }

    unsafe fn create_surface(
        &self,
        target: crate::SurfaceTargetUnsafe,
    ) -> Result<dispatch::DispatchSurface, crate::CreateSurfaceError> {
        match target {
            SurfaceTargetUnsafe::RawHandle {
                raw_display_handle: _,

View on GitHub (pinned to 3e11ff59bf)