gfx-rs/wgpu · error

expected valid handle for canvas

Error message

expected valid handle for canvas

What it means

create_surface on the web backend panics when the raw window/canvas handle passed to it is not one of the recognized web surface targets (an HTMLCanvasElement or OffscreenCanvas). The 'Params' hit in benches is unrelated code; the actual condition is that SurfaceTargetRaw or the converted handle did not match any supported web canvas variant.

Source

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

                            .expect("expected to find single canvas")
                            .into();
                        canvas_node.into()
                    }
                    raw_window_handle::RawWindowHandle::WebCanvas(handle) => {
                        let value: &JsValue = unsafe { handle.obj.cast().as_ref() };
                        value.clone().unchecked_into()
                    }
                    raw_window_handle::RawWindowHandle::WebOffscreenCanvas(handle) => {
                        let value: &JsValue = unsafe { handle.obj.cast().as_ref() };
                        let canvas: web_sys::OffscreenCanvas = value.clone().unchecked_into();
                        let context_result = canvas.get_context("webgpu");

                        return self.create_surface_from_context(
                            Canvas::Offscreen(canvas),
                            context_result,
                        );
                    }
                    _ => panic!("expected valid handle for canvas"),
                };

                let context_result = canvas_element.get_context("webgpu");
                self.create_surface_from_context(Canvas::Canvas(canvas_element), context_result)
            }
        }
    }

    fn request_adapter(
        &self,
        options: &crate::RequestAdapterOptions<'_, '_>,
    ) -> Pin<Box<dyn dispatch::RequestAdapterFuture>> {
        let requested_backends = self.requested_backends;

        //TODO: support this check, return `None` if the flag is not set.
        // It's not trivial, since we need the Future logic to have this check,
        // and currently the Future here has no room for extra parameter `backends`.
        if !(requested_backends.contains(wgt::Backends::BROWSER_WEBGPU)) {

View on GitHub (pinned to 3e11ff59bf)

Solutions

  1. On web, create surfaces from an HTMLCanvasElement or OffscreenCanvas (or pass the canvas via raw handle tagged as web canvas) rather than native window handles.
  2. Use a raw-window-handle web variant (WebCanvas/WebDisplayHandle) that carries the DOM canvas id.
  3. Gate surface creation code per-platform so native handles never reach the wasm build.

Example fix

// before
let surface = instance.create_surface(native_window).unwrap(); // wasm32: panics
// after (web)
let surface = instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas_element)).unwrap();
Defensive patterns

Strategy: validation

Validate before calling

// only pass DOM canvases as surface targets on wasm
assert!(cfg!(target_arch = "wasm32") == canvas_is_web_target, "native window handles cannot create surfaces on web");

Type guard

fn is_valid_web_surface_target(t: &wgpu::SurfaceTargetRaw) -> bool {
    matches!(t, wgpu::SurfaceTargetRaw::WebCanvas(_) | wgpu::SurfaceTargetRaw::WebOffscreenCanvas(_))
}

Prevention

When it happens

Trigger: Calling instance.create_surface with a raw handle whose downcast to a web canvas type fails, e.g. passing a native window handle (Window, VkSurfaceKHR, etc.) to a wasm32-web build, or a corrupted/unexpected SurfaceTargetRaw enum value.

Common situations: Shared cross-platform code passing native window handles on web; using RawWindowHandle from a non-DOM source; mixing wgpu versions where SurfaceTarget variants changed.

Related errors


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