gfx-rs/wgpu · critical

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

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.

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)

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.