zed-industries/zed · error
measuring Canvas text
Error message
measuring Canvas text: {error:?} What it means
Thrown in measure() when canvas.context.measure_text(text) returns a rejected JS promise or throws, after configure(css_font) succeeded. It means the browser refused to compute text metrics for the given text/font on the shared OffscreenCanvas — usually a browser-internal error from the 2D context (empty or invalid font state, oversized string, or a context that has been invalidated), not a problem with the caller's text.
Solutions
- Retry the measurement once with a freshly created OffscreenCanvas, as the 2D context may have become invalid
- Fall back to approximating metrics from a default font (e.g. cache last-good advance/ascent/descent for the font) so layout can proceed
- Log the JsValue error via js_sys::Error::from to surface the browser's message before deciding on retry vs fallback
- Sanity-check css_font against known-good values before calling, since a silently ignored bad font leaves the context in a reset ('10px sans-serif') state
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at crates/gpui_web/src/canvas_text.rs:93 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19).
Data as JSON: /api/errors/7a77318f49effcb9.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gpui_web/src/canvas_text.rs:93
.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")?,
)
})
}
pub(crate) fn measure(text: &str, css_font: &str) -> Result<CanvasTextMetrics> {
with_canvas(|canvas| {
canvas.configure(css_font)?;
let metrics = canvas
.context
.measure_text(text)
.map_err(|error| anyhow!("measuring Canvas text: {error:?}"))?;
let metrics = CanvasTextMetrics {
advance: metrics.width() as f32,
left: -metrics.actual_bounding_box_left() as f32,
right: metrics.actual_bounding_box_right() as f32,
ascent: metrics.actual_bounding_box_ascent() as f32,
descent: metrics.actual_bounding_box_descent() as f32,
};
ensure!(
[
metrics.advance,
metrics.left,
metrics.right,
metrics.ascent,
metrics.descent
]
.into_iter()
.all(f32::is_finite),
"Canvas returned non-finite text metrics"View on GitHub (pinned to 916fc2b8cb)