zed-industries/zed · error

setting Canvas readback option

Error message

setting Canvas readback option: {error:?}

What it means

TextCanvas::new sets the willReadFrequently option on the context-options object via js_sys::Reflect::set. If the JS call throws or returns false, this error (or the following ensure!) is raised. It means the canvas context options object could not be configured, so glyph readback would be inefficient or misconfigured.

Solutions

  1. Inspect the {error:?} payload for the underlying JS exception; it is usually an environment/runtime bug, not app input.
  2. Update wasm-bindgen/web-sys versions to match, as cross-realm Reflect issues are often version-skew bugs.
  3. As a last resort, drop willReadFrequently (it is a performance hint) and construct the context without it.

Example fix

// before
Reflect::set(&options, &"willReadFrequently".into(), &JsValue::TRUE)
    .map_err(|error| anyhow!("setting Canvas readback option: {error:?}"))?;
// after
let assigned = Reflect::set(&options, &"willReadFrequently".into(), &JsValue::TRUE)
    .map_err(|error| anyhow!("setting Canvas readback option: {error:?}"))?;
if !assigned {
    log::warn!("willReadFrequently not set; continuing without readback hint");
}
Defensive patterns

Strategy: try-catch

Try / catch

// Treat the readback hint as optional; never fail text rendering because of it.
if let Err(error) = set_readback_hint(&mut options) {
    web_sys::console::warn_1(&format!("readback hint not set: {error:?}").into());
}

Prevention

When it happens

Trigger: Reflect::set on the freshly created object throws (rare, e.g. cross-realm or frozen object) or returns Ok(false) (property non-writable), which trips `ensure!(assigned, ...)`. Note this message only covers the map_err branch; a false return produces the 'could not be set' error.

Common situations: Exotic embedded JS runtimes or CSP/realm issues where web_sys object manipulation misbehaves; a bug in option-object construction upstream.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

}

struct TextCanvas {
    canvas: OffscreenCanvas,
    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");

View on GitHub (pinned to 916fc2b8cb)