{"record":{"id":"deda419e9f47c9f6","repo":"zed-industries/zed","slug":"canvas-text-font-is-empty","errorCode":null,"errorMessage":"Canvas text font is empty","messagePattern":"Canvas text font is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui_web/src/canvas_text.rs","lineNumber":51,"sourceCode":"        // Every rasterized glyph is read back for upload into GPUI's atlas.\n        let assigned = js_sys::Reflect::set(\n            &options,\n            &JsValue::from_str(\"willReadFrequently\"),\n            &JsValue::TRUE,\n        )\n        .map_err(|error| anyhow!(\"setting Canvas readback option: {error:?}\"))?;\n        ensure!(assigned, \"Canvas readback option could not be set\");\n        let context = canvas\n            .get_context_with_context_options(\"2d\", &options)\n            .map_err(|error| anyhow!(\"getting OffscreenCanvas 2D context: {error:?}\"))?\n            .context(\"OffscreenCanvas 2D text rendering is unavailable\")?\n            .dyn_into::<OffscreenCanvasRenderingContext2d>()\n            .map_err(|error| anyhow!(\"unexpected OffscreenCanvas 2D context: {error:?}\"))?;\n        Ok(Self { canvas, context })\n    }\n\n    fn configure(&self, css_font: &str) -> Result<()> {\n        ensure!(!css_font.trim().is_empty(), \"Canvas text font is empty\");\n        // An invalid CSS font assignment is ignored by Canvas. Reset first so\n        // it cannot accidentally inherit the preceding request's font.\n        self.context.set_font(\"10px sans-serif\");\n        self.context.set_font(css_font);\n        self.context.set_text_align(\"left\");\n        self.context.set_text_baseline(\"alphabetic\");\n        self.context.set_fill_style_str(\"white\");\n        // web-sys does not expose direction on the offscreen 2D context.\n        let assigned = js_sys::Reflect::set(\n            self.context.as_ref(),\n            &JsValue::from_str(\"direction\"),\n            &JsValue::from_str(\"ltr\"),\n        )\n        .map_err(|error| anyhow!(\"setting Canvas text direction: {error:?}\"))?;\n        ensure!(assigned, \"Canvas text direction could not be set\");\n        Ok(())\n    }\n}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/zed-industries/zed/blob/916fc2b8cb3a815cbef4a3b40e13081be72036b6/crates/gpui_web/src/canvas_text.rs#L33-L69","documentation":"Raised in `TextCanvas::configure` when the CSS font string passed for canvas text rendering is empty or whitespace-only. Canvas silently ignores empty/invalid font assignments, so the library fails fast with a clear error instead of rendering text with a stale or default font. Called from `intercept_debug_sessions` during canvas text setup.","triggerScenarios":"Passing an empty string, a string of only spaces, or an unset/None-defaulted font value into the canvas text configuration path (e.g. `configure(\"\")` or a font style that resolved to nothing).","commonSituations":"Font resolution failing upstream so an empty CSS font string reaches the canvas, theme/font configuration missing a font-family entry, or text style defaults not being populated before text layout runs.","solutions":["Ensure the font style resolves to a non-empty CSS font string before calling configure","Check the font-family/font-size inputs feeding this code path (e.g. theme settings, buffer font config)","Add a default fallback font (e.g. '12px sans-serif') when resolution produces an empty value","Log the incoming css_font value to find which caller passes an empty string"],"exampleFix":"// before\ncanvas.configure(&css_font);\n// after\nlet css_font = if css_font.trim().is_empty() {\n    \"12px sans-serif\".to_string()\n} else {\n    css_font\n};\ncanvas.configure(&css_font);","handlingStrategy":"validation","validationCode":"fn ensure_css_font(css_font: &str) -> Result<()> {\n    anyhow::ensure!(!css_font.trim().is_empty(), \"font must be a non-empty CSS font string\");\n    Ok(())\n}\n// call ensure_css_font(&font)? before canvas.configure(&font);","typeGuard":"fn is_valid_css_font(css_font: &str) -> bool {\n    !css_font.trim().is_empty()\n}","tryCatchPattern":"match canvas.configure(&css_font) {\n    Err(e) if e.to_string().contains(\"font is empty\") => {\n        canvas.configure(\"12px sans-serif\")? // fallback font\n    }\n    Err(e) => return Err(e),\n    Ok(()) => (),\n}","preventionTips":["Resolve fonts to a concrete CSS string (family + size + weight) before text measurement","Provide a default/fallback font at the theme/config layer","Fail or default early when font resolution returns empty rather than passing empty strings downward","Add a unit test asserting the style-to-CSS-font conversion never yields an empty string"],"tags":["canvas","font","validation","wasm"],"backgroundTag":"empty-required-field","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"}