zed-industries/zed · error
Canvas text bounds exceed device coordinates
Error message
Canvas text bounds exceed device coordinates
What it means
Before rasterizing a fallback glyph, the web text system computes device-pixel bounds by combining the measured metrics (left, ascent, right, descent) with the subpixel offset and 1px padding, flooring/ceil-ing to integers. It validates that all four edges fit within i32 device coordinates; otherwise it refuses to rasterize with this error, protecting downstream i32 casts and the GPU atlas from overflow.
Solutions
- Validate/clamp font_size before requesting raster bounds — it must be finite and reasonably small (e.g. < 10_000px)
- Check where params/offsets come from; a runaway animation or layout loop can inflate the origin — clamp the offset
- Verify canvas_text::measure is returning sane metrics for the glyph (compare against expected ascent/descent)
- If extreme sizes are legitimate, rasterize in tiles or downscale instead of asking for one giant bitmap
Example fix
// before
let font_size = params.font_size; // possibly huge/NaN from layout
let bounds = text_system.glyph_raster_bounds(params)?;
// after
let font_size = params.font_size;
if !(font_size.is_finite() && font_size > 0.0 && font_size < px(4096.0)) {
return Ok(Rect::default()); // skip rasterizing degenerate/huge glyphs
}
let bounds = text_system.glyph_raster_bounds(params)?; Defensive patterns
Strategy: validation
Validate before calling
fn raster_bounds_are_safe(font_size: Pixels, offset: (f64, f64)) -> bool {
font_size.is_finite()
&& font_size > px(0.0)
&& font_size.0 < 10_000.0
&& offset.0.is_finite()
&& offset.1.is_finite()
&& offset.0.abs() < f64::from(i32::MAX / 4)
&& offset.1.abs() < f64::from(i32::MAX / 4)
} Type guard
fn finite_f64(value: f64) -> Option<f64> {
value.is_finite().then_some(value)
} Try / catch
match text_system.glyph_raster_bounds(¶ms) {
Ok(bounds) => bounds,
Err(err) if err.to_string().contains("exceed device coordinates") => {
// glyph origin/size is pathological; skip or clamp instead of crashing layout
Rect::default()
}
Err(err) => return Err(err),
} Prevention
- Clamp animated font sizes to a sane maximum (e.g. a few thousand px)
- Check tween/animation code for runaway values before they reach text rasterization
- Validate viewport/scale factors so NaN or zero measurements never propagate into glyph params
- Skip rasterization for glyphs far outside the visible viewport
When it happens
Trigger: Calling glyph_raster_bounds (reached via fallback_glyph) with font_size, subpixel offsets, or measured metrics large enough that left/top/right/bottom exceed i32::MIN..i32::MAX after the floor/ceil operations — e.g. an enormous font size, NaN/large metrics from canvas_text::measure, or a bogus negative/left shift producing out-of-range values.
Common situations: Rendering text with an absurd font size (millions of pixels) coming from a bad animation/tween or a units mix-up, a Canvas measurement returning garbage (NaN would fail the ensure too), or layout bugs where the glyph origin drifts far outside the device viewport.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Canvas returned a negative advance
- invalid Canvas font size
- Canvas font ID space exhausted
- Canvas readback option could not be set
- Canvas returned non-finite text metrics
AI-assisted analysis of zed-industries/zed@916fc2b8cb (2026-09-19).
Data as JSON: /api/errors/37f1296a868dadfb.
Report an issue: GitHub.
Appendix: source
Thrown at crates/gpui_web/src/text_system.rs:359
fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
if self.canvas_font(params.font_id).is_none() {
return self.native.glyph_raster_bounds(params);
}
let metrics = self.measure(
params.font_id,
params.glyph_id,
params.font_size * params.scale_factor,
)?;
if metrics.right <= metrics.left || metrics.ascent + metrics.descent <= 0. {
return Ok(Bounds::default());
}
let (offset_x, offset_y) = subpixel_offset(params);
let left = (f64::from(metrics.left) + f64::from(offset_x)).floor() - 1.;
let top = (-f64::from(metrics.ascent) + f64::from(offset_y)).floor() - 1.;
let right = (f64::from(metrics.right) + f64::from(offset_x)).ceil() + 1.;
let bottom = (f64::from(metrics.descent) + f64::from(offset_y)).ceil() + 1.;
ensure!(
[left, top, right, bottom]
.into_iter()
.all(|value| value >= f64::from(i32::MIN) && value <= f64::from(i32::MAX)),
"Canvas text bounds exceed device coordinates"
);
let width = (right as i32)
.checked_sub(left as i32)
.context("Canvas text width overflow")?;
let height = (bottom as i32)
.checked_sub(top as i32)
.context("Canvas text height overflow")?;
Ok(Bounds {
origin: point((left as i32).into(), (top as i32).into()),
size: size(width.into(), height.into()),
})
}
fn rasterize_glyph(View on GitHub (pinned to 916fc2b8cb)