zed-industries/zed · error
Canvas text direction could not be set
Error message
Canvas text direction could not be set
What it means
Raised in `TextCanvas::configure` when assigning `direction = "ltr"` on the OffscreenCanvasRenderingContext2d via `js_sys::Reflect::set` completes without an exception but returns `false`, meaning the property write was rejected. The library forces left-to-right direction for deterministic text measurement, and treats a rejected assignment as fatal since subsequent text metrics would be unreliable. This mirrors the readback-option check in `new` and indicates an unusual JS environment or a context object that rejects property writes.
Solutions
- Run in an up-to-date browser with full CanvasRenderingContext2D.direction support
- If using a canvas mock/shim in tests, define properties as writable or implement a setter that returns true
- Check for proxies intercepting the context object and allow-list the 'direction' property
- Fall back to not setting direction (accepting default) if the environment cannot support it
Example fix
// before
ensure!(assigned, "Canvas text direction could not be set");
// after
if !assigned {
log::warn!("Canvas text direction could not be set; relying on default direction");
}
Ok(()) Defensive patterns
Strategy: try-catch
Validate before calling
// probe whether the context accepts property writes before configuring
let probe = js_sys::Reflect::set(
context.as_ref(),
&JsValue::from_str("direction"),
&JsValue::from_str("ltr"),
).unwrap_or(false);
if !probe { log::warn!("context rejects direction writes; metrics may vary"); } Type guard
fn context_accepts_writes(context: &js_sys::Object) -> bool {
!js_sys::Object::is_frozen(context) && !js_sys::Object::is_sealed(context)
} Try / catch
match canvas.configure(&css_font) {
Err(e) if e.to_string().contains("direction could not be set") => {
// proceed with default direction; log for diagnostics
log::warn!("direction ltr unsupported: {e}");
}
Err(e) => return Err(e),
Ok(()) => (),
} Prevention
- Keep canvas context objects un-frozen and un-sealed throughout their lifetime
- Use current browser versions; 'direction' support on 2D contexts is broad but not universal
- Avoid wrapping the context in JS proxies in test shims
- Treat direction assignment as best-effort and degrade gracefully rather than failing hard where text direction is not critical
When it happens
Trigger: The rendering context object is frozen/sealed or wrapped in a proxy that rejects writes, the JS engine does not implement the writable `direction` property on 2D contexts, or the context was replaced by a mock in tests with non-writable properties.
Common situations: Non-standard embedding runtimes (Node-based wasm testing with canvas mocks), browser versions lacking full CanvasRenderingContext2D.direction support, or test double objects whose property descriptors are non-writable.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Canvas readback option could not be set
- setting Canvas readback option
- Canvas returned non-finite text metrics
- Canvas text font is empty
- Canvas text raster exceeds maximum dimension
AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19).
Data as JSON: /api/errors/4a50f21009d6786a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gpui_web/src/canvas_text.rs:66
}
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(),
&JsValue::from_str("direction"),
&JsValue::from_str("ltr"),
)
.map_err(|error| anyhow!("setting Canvas text direction: {error:?}"))?;
ensure!(assigned, "Canvas text direction could not be set");
Ok(())
}
}
fn with_canvas<T>(operation: impl FnOnce(&mut TextCanvas) -> Result<T>) -> Result<T> {
CANVAS.with(|canvas| {
let mut canvas = canvas
.try_borrow_mut()
.context("Canvas text renderer was called reentrantly")?;
if canvas.is_none() {
*canvas = Some(TextCanvas::new()?);
}
operation(
canvas
.as_mut()
.context("Canvas text renderer is unavailable")?,
)
})View on GitHub (pinned to 916fc2b8cb)