zed-industries/zed · error

getting OffscreenCanvas 2D context

Error message

getting OffscreenCanvas 2D context: {error:?}

What it means

After building the options object, TextCanvas::new requests a '2d' context from the OffscreenCanvas via get_context_with_context_options. If the browser throws or returns a JS error, this anyhow error wraps it. This indicates the 2D context could not be created at all (distinct from returning null, which yields the 'unavailable' context error).

Solutions

  1. Update the browser to a version with full OffscreenCanvas 2D support (Safari 16.4+, Chrome 69+, Firefox 105+).
  2. Retry creating the context without the willReadFrequently option to rule out option-related rejection.
  3. Fall back to a regular HTMLCanvasElement 2D context when OffscreenCanvas 2D is unavailable.

Example fix

// before
let context = canvas.get_context_with_context_options("2d", &options)?;
// after
let context = canvas
    .get_context_with_context_options("2d", &options)
    .or_else(|_| canvas.get_context("2d"))
    .context("OffscreenCanvas 2D text rendering is unavailable")?;
Defensive patterns

Strategy: fallback

Validate before calling

function supportsOffscreenCanvas2d() {
  try {
    const c = new OffscreenCanvas(1, 1);
    return c.getContext("2d") !== null;
  } catch { return false; }
}

Type guard

fn offscreen_2d_supported(window: &web_sys::Window) -> bool {
    let canvas = web_sys::OffscreenCanvas::new(1, 1).ok()?;
    canvas.get_context("2d").ok()?.flatten().is_some()
}

Try / catch

match TextCanvas::new(width, height) {
    Ok(canvas) => canvas,
    Err(e) if format!("{e:#}").contains("2D context") => switch_to_dom_canvas_backend(),
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Calling get_context_with_context_options("2d", &options) when the engine rejects the call: OffscreenCanvas present but 2D context unsupported, invalid context options, or a JS exception in the call.

Common situations: Browser supports OffscreenCanvas but not its 2D context (older Safari 16.x); context options object malformed due to the earlier Reflect failure; browser bugs with willReadFrequently on OffscreenCanvas.

Related errors


AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19). Data as JSON: /api/errors/e912b4635c4ca4a1. Report an issue: GitHub.

Appendix: source

Thrown at crates/gpui_web/src/canvas_text.rs:43

    context: OffscreenCanvasRenderingContext2d,
}

impl TextCanvas {
    fn new() -> Result<Self> {
        let canvas = OffscreenCanvas::new(1, 1)
            .map_err(|error| anyhow!("creating text OffscreenCanvas: {error:?}"))?;
        let options = js_sys::Object::new();
        // Every rasterized glyph is read back for upload into GPUI's atlas.
        let assigned = js_sys::Reflect::set(
            &options,
            &JsValue::from_str("willReadFrequently"),
            &JsValue::TRUE,
        )
        .map_err(|error| anyhow!("setting Canvas readback option: {error:?}"))?;
        ensure!(assigned, "Canvas readback option could not be set");
        let context = canvas
            .get_context_with_context_options("2d", &options)
            .map_err(|error| anyhow!("getting OffscreenCanvas 2D context: {error:?}"))?
            .context("OffscreenCanvas 2D text rendering is unavailable")?
            .dyn_into::<OffscreenCanvasRenderingContext2d>()
            .map_err(|error| anyhow!("unexpected OffscreenCanvas 2D context: {error:?}"))?;
        Ok(Self { canvas, context })
    }

    fn configure(&self, css_font: &str) -> Result<()> {
        ensure!(!css_font.trim().is_empty(), "Canvas text font is empty");
        // An invalid CSS font assignment is ignored by Canvas. Reset first so
        // it cannot accidentally inherit the preceding request's font.
        self.context.set_font("10px sans-serif");
        self.context.set_font(css_font);
        self.context.set_text_align("left");
        self.context.set_text_baseline("alphabetic");
        self.context.set_fill_style_str("white");
        // web-sys does not expose direction on the offscreen 2D context.
        let assigned = js_sys::Reflect::set(
            self.context.as_ref(),

View on GitHub (pinned to 916fc2b8cb)