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

  1. Fix the first panic: reproduce with RUST_BACKTRACE=1 and look at the earliest failure
  2. Shut down or restart after any caught text panic instead of continuing to render
  3. Isolate custom background text work with catch_unwind
  4. 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

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


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)