{"record":{"id":"37f1296a868dadfb","repo":"zed-industries/zed","slug":"canvas-text-bounds-exceed-device-coordinates","errorCode":null,"errorMessage":"Canvas text bounds exceed device coordinates","messagePattern":"Canvas text bounds exceed device coordinates","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui_web/src/text_system.rs","lineNumber":359,"sourceCode":"\n    fn glyph_raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {\n        if self.canvas_font(params.font_id).is_none() {\n            return self.native.glyph_raster_bounds(params);\n        }\n        let metrics = self.measure(\n            params.font_id,\n            params.glyph_id,\n            params.font_size * params.scale_factor,\n        )?;\n        if metrics.right <= metrics.left || metrics.ascent + metrics.descent <= 0. {\n            return Ok(Bounds::default());\n        }\n        let (offset_x, offset_y) = subpixel_offset(params);\n        let left = (f64::from(metrics.left) + f64::from(offset_x)).floor() - 1.;\n        let top = (-f64::from(metrics.ascent) + f64::from(offset_y)).floor() - 1.;\n        let right = (f64::from(metrics.right) + f64::from(offset_x)).ceil() + 1.;\n        let bottom = (f64::from(metrics.descent) + f64::from(offset_y)).ceil() + 1.;\n        ensure!(\n            [left, top, right, bottom]\n                .into_iter()\n                .all(|value| value >= f64::from(i32::MIN) && value <= f64::from(i32::MAX)),\n            \"Canvas text bounds exceed device coordinates\"\n        );\n        let width = (right as i32)\n            .checked_sub(left as i32)\n            .context(\"Canvas text width overflow\")?;\n        let height = (bottom as i32)\n            .checked_sub(top as i32)\n            .context(\"Canvas text height overflow\")?;\n        Ok(Bounds {\n            origin: point((left as i32).into(), (top as i32).into()),\n            size: size(width.into(), height.into()),\n        })\n    }\n\n    fn rasterize_glyph(","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/zed-industries/zed/blob/916fc2b8cb3a815cbef4a3b40e13081be72036b6/crates/gpui_web/src/text_system.rs#L341-L377","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet font_size = params.font_size; // possibly huge/NaN from layout\nlet bounds = text_system.glyph_raster_bounds(params)?;\n// after\nlet font_size = params.font_size;\nif !(font_size.is_finite() && font_size > 0.0 && font_size < px(4096.0)) {\n    return Ok(Rect::default()); // skip rasterizing degenerate/huge glyphs\n}\nlet bounds = text_system.glyph_raster_bounds(params)?;","handlingStrategy":"validation","validationCode":"fn raster_bounds_are_safe(font_size: Pixels, offset: (f64, f64)) -> bool {\n    font_size.is_finite()\n        && font_size > px(0.0)\n        && font_size.0 < 10_000.0\n        && offset.0.is_finite()\n        && offset.1.is_finite()\n        && offset.0.abs() < f64::from(i32::MAX / 4)\n        && offset.1.abs() < f64::from(i32::MAX / 4)\n}","typeGuard":"fn finite_f64(value: f64) -> Option<f64> {\n    value.is_finite().then_some(value)\n}","tryCatchPattern":"match text_system.glyph_raster_bounds(&params) {\n    Ok(bounds) => bounds,\n    Err(err) if err.to_string().contains(\"exceed device coordinates\") => {\n        // glyph origin/size is pathological; skip or clamp instead of crashing layout\n        Rect::default()\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["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"],"tags":["fonts","canvas","rasterization","overflow"],"backgroundTag":"value-out-of-range","analyzedSha":"916fc2b8cb3a815cbef4a3b40e13081be72036b6","analyzedAt":"2026-09-19T19:09:50.599Z","contentChangedAt":"2026-09-19T19:09:50.599Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}