zed-industries/zed · error
invalid Canvas font size
Error message
invalid Canvas font size
What it means
CanvasFont::css_font builds the CSS font shorthand string (e.g. "italic 700 16px family") that is passed to the browser's canvas text APIs. Canvas requires a finite, positive font size; if the incoming Pixels value is NaN, infinite, zero, or negative, the method throws this error instead of producing an invalid CSS font string that the browser would silently reject.
Solutions
- Clamp font_size at the call site: if !size.is_finite() || size <= 0.0, substitute a sane default before invoking text measurement
- Trace where the NaN/zero/negative size originates (often a division by zero scale or an unmeasured parent)
- Give text styles a positive default font size in config/theme instead of 0.0
- Defer measurement until layout has produced real dimensions (e.g. skip measuring while viewport size is 0)
Example fix
// before
let font_size = style.font_size; // may be 0.0 or NaN
let metrics = text_system.layout_line(...)?;
// after
let font_size = if style.font_size.is_finite() && style.font_size > px(0.0) {
style.font_size
} else {
px(16.0) // sane default instead of invalid Canvas font size
};
let metrics = text_system.layout_line(...)?; Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_canvas_font_size(size: Pixels) -> bool {
size.0.is_finite() && size.0 > 0.0
}
// guard before any text measurement call
if !is_valid_canvas_font_size(style.font_size) { style.font_size = px(16.0); } Type guard
fn valid_font_size(size: Pixels) -> Option<Pixels> {
(size.0.is_finite() && size.0 > 0.0).then_some(size)
} Try / catch
match text_system.layout_line(line, font_size, ...) {
Ok(result) => result,
Err(err) if err.to_string().contains("invalid Canvas font size") => {
// retry with a safe default size
text_system.layout_line(line, px(16.0), ...)?
}
Err(err) => return Err(err),
} Prevention
- Never initialize text styles with font_size 0.0 or a computed value that can be NaN
- Clamp scale/zoom-derived font sizes: size = raw_size.max(px(1.0))
- Defer text measurement until parent layout has real (non-zero) dimensions
- Unit-test theme/config parsing so a non-positive default size is caught early
When it happens
Trigger: Calling css_font (via measure, typographic_bounds, advance, or glyph rasterization paths on a Canvas font) with a font_size that is non-finite or <= 0 — e.g. NaN/inf from a failed layout computation, a zero size from an empty window/viewport, or negative sizes from sign errors in scaling code.
Common situations: A text style whose font_size was divided by a zero scale factor (NaN), a zoom/animation tween passing through 0, a viewport measurement of 0 before layout settles, or a misconfigured theme providing a non-positive default size.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Canvas returned a negative advance
- Canvas text bounds exceed device coordinates
- Canvas text font is empty
- Cannot remove a keybinding that does not exist
- Canvas font ID space exhausted
AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19).
Data as JSON: /api/errors/3848c8abd5843575.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gpui_web/src/text_system.rs:449
}
fn recommended_rendering_mode(&self, font_id: FontId, font_size: Pixels) -> TextRenderingMode {
if self.canvas_font(font_id).is_some() {
TextRenderingMode::Grayscale
} else {
self.native.recommended_rendering_mode(font_id, font_size)
}
}
fn glyph_dilation_for_color(&self, color: Hsla) -> u8 {
self.native.glyph_dilation_for_color(color)
}
}
impl CanvasFont {
fn css_font(&self, font_size: Pixels, color: bool) -> Result<String> {
let font_size = f32::from(font_size);
ensure!(
font_size.is_finite() && font_size > 0.,
"invalid Canvas font size"
);
let style = match self.descriptor.style {
FontStyle::Normal => "normal",
FontStyle::Italic => "italic",
FontStyle::Oblique => "oblique",
};
let mut families = Vec::new();
if !color && !self.descriptor.family.starts_with('.') {
families.push(quote_family(&self.descriptor.family));
}
if let Some(fallbacks) = &self.descriptor.fallbacks {
families.extend(
fallbacks
.fallback_list()
.iter()
.map(|family| quote_family(family)),View on GitHub (pinned to 916fc2b8cb)