iced-rs/iced · error
Read font system
Error message
Read font system
What it means
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.
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
Example fix
// before - after a caught text panic the next frame dies in compare
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| warm_up_text()));
// next draw: paragraph.compare(...) -> panic "Read font system"
// after - fail fast on the first text panic
if std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| warm_up_text())).is_err() {
std::process::abort();
} Defensive patterns
Strategy: validation
Validate before calling
if iced_graphics::text::font_system().is_poisoned() {
return Err("font system poisoned by an earlier panic".into());
}
let difference = paragraph.compare(text.into()); Try / catch
if std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| paragraph.compare(text.into()))).is_err() {
// the read side is poisoned too: rendering cannot continue
std::process::abort();
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Write font system
- Write font system
- Line layout should be cached
- primitive storage should be writable
- Read primitive storage
AI-assisted analysis of iced-rs/iced@fa3bae5287 (2026-08-17).
Data as JSON: /api/errors/9e74aab4355d5ebc.
Report an issue: GitHub.
Appendix: source
Thrown at graphics/src/text/paragraph.rs:233
paragraph.buffer.set_size(
Some(new_bounds.width * paragraph.hint_factor),
Some(new_bounds.height * paragraph.hint_factor),
);
paragraph
.buffer
.shape_until_scroll(font_system.raw(), false);
let min_bounds = text::align(&mut paragraph.buffer, font_system.raw(), paragraph.align_x)
/ paragraph.hint_factor;
paragraph.bounds = new_bounds;
paragraph.min_bounds = min_bounds;
}
fn compare(&self, text: Text<()>) -> core::text::Difference {
let font_system = text::font_system().read().expect("Read font system");
let paragraph = self.internal();
let metrics = paragraph.buffer.metrics();
if paragraph.version != font_system.version
|| metrics.font_size != text.size.0 * paragraph.hint_factor
|| metrics.line_height
!= text.line_height.to_absolute(text.size).0 * paragraph.hint_factor
|| paragraph.font != text.font
|| paragraph.shaping != text.shaping
|| paragraph.wrapping != text.wrapping
|| paragraph.ellipsis != text.ellipsis
|| paragraph.align_x != text.align_x
|| paragraph.align_y != text.align_y
|| paragraph.hint.then_some(paragraph.hint_factor)
!= text::hint_factor(text.size, text.hint_factor)
{
core::text::Difference::Shape
} else if paragraph.bounds != text.bounds {
core::text::Difference::Bounds
} else {View on GitHub (pinned to fa3bae5287)