a-b-street/abstreet · error · anyhow::Error

unable to cast to WebGl2RenderingContext. error

Error message

unable to cast to WebGl2RenderingContext. error: {:?}

What it means

After obtaining the WebGL 2 context object, it must be cast via dyn_into::<WebGl2RenderingContext>. If the returned JsValue is not actually a WebGl2RenderingContext (unexpected object type from the bindings), the cast fails and this error is raised. This is a wasm-bindgen type mismatch, rare in practice.

Solutions

  1. Update and align web-sys and wasm-bindgen versions (cargo update) and rebuild the wasm target.
  2. Clear stale build artifacts (cargo clean, rm -rf target) to regenerate bindings.
  3. Test in a standard browser to rule out getContext shims or extension interference.
  4. Log the failing JsValue to identify what object was actually returned.

Example fix

// before
.dyn_into::<web_sys::WebGl2RenderingContext>()
.map_err(|err| anyhow!("unable to cast to WebGl2RenderingContext. error: {:?}", err))?;
// after: dependency alignment
// Cargo.toml: keep web-sys and wasm-bindgen on matching, current versions
// then: cargo clean && cargo build --target wasm32-unknown-unknown
Defensive patterns

Strategy: retry

Try / catch

// Retry once after a clean rebuild on cast failure
match webgl2_glow_context(canvas) {
    Err(e) if e.to_string().contains("unable to cast") => {
        // usually stale bindings: advise cargo clean + aligned deps, then retry
        Err(anyhow!("stale wasm bindings? run: cargo clean && cargo build --target wasm32-unknown-unknown"))
    }
    other => other,
}

Prevention

When it happens

Trigger: canvas.get_context("webgl2") returns a JsValue that fails dyn_into::<web_sys::WebGl2RenderingContext>() — e.g., a mismatched web-sys version, a context acquired as a different interface, or unusual browser/proxy behavior.

Common situations: Version mismatch between web-sys/wasm-bindgen crates and generated bindings; running in environments that shim getContext with non-standard objects; build caches with stale bindings after upgrading dependencies.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/40606ccd8cffe17a. Report an issue: GitHub.

Appendix: source

Thrown at widgetry/src/backend_glow_wasm.rs:90

                "failed to build WebGL 2.0 context with error: \"{}\". Trying WebGL 1.0 instead...",
                err
            );
            webgl1_glow_context(&canvas).and_then(|gl| {
                is_gl2 = false;
                webgl1_program(gl)
            })
        })
        .unwrap();

    fn webgl2_glow_context(canvas: &web_sys::HtmlCanvasElement) -> Result<glow::Context> {
        let maybe_context: Option<_> = canvas
            .get_context("webgl2")
            .map_err(|err| anyhow!("error getting context for WebGL 2.0: {:?}", err))?;
        let js_webgl2_context =
            maybe_context.ok_or(anyhow!("Browser doesn't support WebGL 2.0"))?;
        let webgl2_context = js_webgl2_context
            .dyn_into::<web_sys::WebGl2RenderingContext>()
            .map_err(|err| anyhow!("unable to cast to WebGl2RenderingContext. error: {:?}", err))?;
        Ok(glow::Context::from_webgl2_context(webgl2_context))
    }

    fn webgl1_glow_context(canvas: &web_sys::HtmlCanvasElement) -> Result<glow::Context> {
        let maybe_context: Option<_> = canvas
            .get_context("webgl")
            .map_err(|err| anyhow!("error getting context for WebGL 1.0: {:?}", err))?;
        let js_webgl1_context =
            maybe_context.ok_or(anyhow!("Browser doesn't support WebGL 1.0"))?;
        let webgl1_context = js_webgl1_context
            .dyn_into::<web_sys::WebGlRenderingContext>()
            .map_err(|err| anyhow!("unable to cast to WebGlRenderingContext. error: {:?}", err))?;
        Ok(glow::Context::from_webgl1_context(webgl1_context))
    }

    (
        PrerenderInnards::new(gl, is_gl2, program, Some(WindowAdapter(winit_window))),
        event_loop,

View on GitHub (pinned to 0964f29315)