{"record":{"id":"767c3c444dc96526","repo":"iced-rs/iced","slug":"write-font-system","errorCode":null,"errorMessage":"Write font system","messagePattern":"Write font system","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graphics/src/geometry/text.rs","lineNumber":84,"sourceCode":"\n        let translation_x = match self.align_x {\n            Alignment::Default | Alignment::Left | Alignment::Justified => self.position.x,\n            Alignment::Center => self.position.x - paragraph.min_width() / 2.0,\n            Alignment::Right => self.position.x - paragraph.min_width(),\n        };\n\n        let translation_y = {\n            match self.align_y {\n                alignment::Vertical::Top => self.position.y,\n                alignment::Vertical::Center => self.position.y - paragraph.min_height() / 2.0,\n                alignment::Vertical::Bottom => self.position.y - paragraph.min_height(),\n            }\n        };\n\n        let buffer = paragraph.buffer();\n        let mut swash_cache = cosmic_text::SwashCache::new();\n\n        let mut font_system = text::font_system().write().expect(\"Write font system\");\n\n        for run in buffer.layout_runs() {\n            for glyph in run.glyphs.iter() {\n                let physical_glyph = glyph.physical((0.0, 0.0), 1.0);\n\n                let start_x = translation_x + glyph.x + glyph.x_offset;\n                let start_y = translation_y + glyph.y_offset + run.line_y;\n                let offset = Vector::new(start_x, start_y);\n\n                if let Some(commands) =\n                    swash_cache.get_outline_commands(font_system.raw(), physical_glyph.cache_key)\n                {\n                    let glyph = Path::new(|path| {\n                        use cosmic_text::Command;\n\n                        for command in commands {\n                            match command {\n                                Command::MoveTo(p) => {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/iced-rs/iced/blob/2cffa99b395d84fe469b44dccb56bbacd2f1a157/graphics/src/geometry/text.rs#L66-L102","documentation":"The CPU text-outline path (stroked text in iced's geometry/canvas API) takes the global font-system write lock to shape glyph outlines via the swash cache. `.expect(\"Write font system\")` panics if that lock is poisoned; calling it re-entrantly while the same thread already holds a font-system guard would deadlock instead.","triggerScenarios":"Drawing stroked/outlined text in a canvas frame once another thread has panicked inside a critical section of the shared font system; outlining text from inside a callback that itself is running under a font-system lock.","commonSituations":"Canvas-heavy apps mixing stroke text with filled text after any swallowed panic in the text pipeline; debug rendering overlays that outline glyphs on multiple threads.","solutions":["Find and fix the original panic under the font-system lock — this expect is collateral","Draw geometry text only on the render thread, never from worker threads","Recover from poison in the library: `write().unwrap_or_else(PoisonError::into_inner)`","Prefer the filled-text path when outline rendering is optional for your visuals"],"exampleFix":"// before\nlet mut font_system = text::font_system().write().expect(\"Write font system\");\n// after\nlet mut font_system = text::font_system()\n    .write()\n    .unwrap_or_else(std::sync::PoisonError::into_inner);","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"let outlined = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    draw_stroked_text(&frame, &paragraph);\n}));\nif outlined.is_err() {\n    draw_filled_text(&frame, &paragraph); // fall back to the filled-text path\n}","preventionTips":["Draw geometry/canvas text only on the render thread, never from worker threads","Never invoke text outlining from inside callbacks that already run under a font-system lock","Prefer the filled-text path when outlines are cosmetic — it avoids the write lock entirely","Treat any first panic in the text pipeline as session-ending; the poisoned lock will cascade here"],"tags":["rust","iced","graphics","text","outline","cosmic-text","rwlock","lock-poisoning","panic"],"backgroundTag":"lock-poisoned","analyzedSha":"2cffa99b395d84fe469b44dccb56bbacd2f1a157","analyzedAt":"2026-08-16T19:41:49.083Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}