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

Browser doesn't support WebGL 1.0

Error message

Browser doesn't support WebGL 1.0

What it means

webgl1_glow_context requests a 'webgl' (WebGL 1.0) context from the HTML canvas via get_context. The browser returned Ok(None), meaning it could not supply a WebGL 1.0 context for this canvas. The library throws this because glow needs a valid WebGL context to render at all; there is no software fallback.

Solutions

  1. Enable WebGL in the browser (chrome://flags / browser settings, hardware acceleration on)
  2. Test in a normal (non-headless) browser with GPU access
  3. Ensure the canvas has no other context type already created on it
  4. Use a browser or device known to support WebGL 1.0; consider a WebGL2 fallback path in setup

Example fix

// before: blindly requesting webgl
let ctx = webgl1_glow_context(&canvas)?;
// after: probe first and fail with a clear message
let supported = js_sys::eval("document.createElement('canvas').getContext('webgl') != null").unwrap().as_bool().unwrap_or(false);
anyhow::ensure!(supported, "WebGL 1.0 unavailable; enable hardware acceleration");
let ctx = webgl1_glow_context(&canvas)?;
Defensive patterns

Strategy: fallback

Validate before calling

let supported = web_sys::window().unwrap().navigator().user_agent().map(|ua| ua.contains("HeadlessChrome")).unwrap_or(false) == false;
let probe = js_sys::eval("!!document.createElement('canvas').getContext('webgl')").unwrap().as_bool().unwrap_or(false);
if !probe { show_no_webgl_message(); return; }

Type guard

function webgl_supported(): boolean {
  try { const c = document.createElement('canvas'); return !!(c.getContext('webgl') || c.getContext('experimental-webgl')); } catch { return false; }
}

Try / catch

match webgl1_glow_context(&canvas) {
    Ok(gl) => start(gl),
    Err(e) => { render_error_page("This app requires WebGL 1.0. Enable hardware acceleration."); }
}

Prevention

When it happens

Trigger: canvas.get_context("webgl") returns None in a wasm browser build: the browser lacks WebGL 1.0 support or WebGL is disabled, the canvas already has a different context type bound, or GPU/driver contexts are exhausted.

Common situations: Running in a headless browser or CI environment without GPU, WebGL disabled via browser flags/policy, browser fallback paths that only implement WebGL2 or no WebGL at all, or the canvas already initialized with a 'webgl2' or '2d' context.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at widgetry/src/backend_glow_wasm.rs:99

    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,
    )
}

fn webgl2_program(gl: glow::Context) -> Result<(glow::Context, glow::Program)> {
    let program = unsafe {
        build_program(
            &gl,
            include_str!("../shaders/vertex_300.glsl"),
            include_str!("../shaders/fragment_300.glsl"),

View on GitHub (pinned to 0964f29315)