{"record":{"id":"9e74aab4355d5ebc","repo":"iced-rs/iced","slug":"read-font-system","errorCode":null,"errorMessage":"Read font system","messagePattern":"Read font system","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graphics/src/text/paragraph.rs","lineNumber":233,"sourceCode":"        paragraph.buffer.set_size(\n            Some(new_bounds.width * paragraph.hint_factor),\n            Some(new_bounds.height * paragraph.hint_factor),\n        );\n        paragraph\n            .buffer\n            .shape_until_scroll(font_system.raw(), false);\n\n        let min_bounds = text::align(&mut paragraph.buffer, font_system.raw(), paragraph.align_x)\n            / paragraph.hint_factor;\n\n        paragraph.bounds = new_bounds;\n        paragraph.min_bounds = min_bounds;\n    }\n\n    fn compare(&self, text: Text<()>) -> core::text::Difference {\n        let font_system = text::font_system().read().expect(\"Read font system\");\n        let paragraph = self.internal();\n        let metrics = paragraph.buffer.metrics();\n\n        if paragraph.version != font_system.version\n            || metrics.font_size != text.size.0 * paragraph.hint_factor\n            || metrics.line_height\n                != text.line_height.to_absolute(text.size).0 * paragraph.hint_factor\n            || paragraph.font != text.font\n            || paragraph.shaping != text.shaping\n            || paragraph.wrapping != text.wrapping\n            || paragraph.ellipsis != text.ellipsis\n            || paragraph.align_x != text.align_x\n            || paragraph.align_y != text.align_y\n            || paragraph.hint.then_some(paragraph.hint_factor)\n                != text::hint_factor(text.size, text.hint_factor)\n        {\n            core::text::Difference::Shape\n        } else if paragraph.bounds != text.bounds {\n            core::text::Difference::Bounds\n        } else {","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/iced-rs/iced/blob/fa3bae52874274c012a27d4bf11a83c49e1709ae/graphics/src/text/paragraph.rs#L215-L251","documentation":"iced keeps one global cosmic-text FontSystem behind a std::sync::RwLock (graphics/src/text.rs:119). Paragraph::compare (graphics/src/text/paragraph.rs:228), which decides whether cached paragraph state matches new text parameters, takes the read lock with .read().expect(\"Read font system\"). This fails only when the lock is poisoned by an earlier panic on a thread that held it in any mode.","triggerScenarios":"Any text comparison/diffing during iced's render loop after an earlier panic inside a font-system critical section (Editor, Paragraph, or custom code) poisoned the global lock.","commonSituations":"The render loop runs compare every frame, so this is often the first symptom after a background or one-off text panic poisoned the lock; common in apps that caught a panic and kept rendering.","solutions":["Fix the first panic: reproduce with RUST_BACKTRACE=1 and look at the earliest failure","Shut down or restart after any caught text panic instead of continuing to render","Isolate custom background text work with catch_unwind","Upgrade iced for upstream panic fixes"],"exampleFix":"// before - after a caught text panic the next frame dies in compare\nlet _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| warm_up_text()));\n// next draw: paragraph.compare(...) -> panic \"Read font system\"\n\n// after - fail fast on the first text panic\nif std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| warm_up_text())).is_err() {\n    std::process::abort();\n}","handlingStrategy":"validation","validationCode":"if iced_graphics::text::font_system().is_poisoned() {\n    return Err(\"font system poisoned by an earlier panic\".into());\n}\nlet difference = paragraph.compare(text.into());","typeGuard":null,"tryCatchPattern":"if std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| paragraph.compare(text.into()))).is_err() {\n    // the read side is poisoned too: rendering cannot continue\n    std::process::abort();\n}","preventionTips":["compare runs every frame, so poison surfaces immediately: fix the first panic","Add a startup smoke test that renders text to catch poisoning early in CI","Never continue rendering after a caught text panic","Upgrade iced"],"tags":["rust","iced","rwlock","poisoned-lock","font-system","cosmic-text","paragraph"],"backgroundTag":"rwlock-poisoned","analyzedSha":"fa3bae52874274c012a27d4bf11a83c49e1709ae","analyzedAt":"2026-08-17T10:40:26.997Z","contentChangedAt":"2026-08-17T10:40:26.997Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}