iced-rs/iced · error

Write to font system

Error message

Write to font system

What it means

`Compositor::load_font` hands custom font bytes to the global cosmic-text `font_system()` behind an `RwLock`; `.write().expect("Write to font system")` panics when that lock is poisoned by an earlier panic during text layout/shaping on another thread. Acquiring the write lock re-entrantly while a read guard is alive on the same thread would deadlock instead.

Source

Thrown at graphics/src/compositor.rs:57

        &mut self,
        window: impl Window + Clone,
        width: u32,
        height: u32,
    ) -> Self::Surface;

    /// Configures a new [`Surface`] with the given dimensions.
    ///
    /// [`Surface`]: Self::Surface
    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32);

    /// Returns [`Information`] used by this [`Compositor`].
    fn information(&self) -> Information;

    /// Loads a font from its bytes.
    fn load_font(&mut self, font: Cow<'static, [u8]>) -> Result<(), font::Error> {
        crate::text::font_system()
            .write()
            .expect("Write to font system")
            .load_font(font);

        // TODO: Error handling
        Ok(())
    }

    /// Lists all the available font families.
    fn list_fonts(&mut self) -> Result<Vec<font::Family>, font::Error> {
        use std::collections::BTreeSet;

        let font_system = crate::text::font_system()
            .read()
            .expect("Read from font system");

        let families = BTreeSet::from_iter(font_system.families());

        Ok(families.into_iter().map(font::Family::name).collect())
    }

View on GitHub (pinned to 2cffa99b39)

Solutions

  1. Find the original panic in the text pipeline — this expect is secondary poisoning
  2. Load all custom fonts at startup, before spawning render/layout work
  3. Recover from poison instead of panicking: `write().unwrap_or_else(PoisonError::into_inner)`
  4. Validate font bytes before handing them to load_font so bad data fails early and cleanly

Example fix

// before
crate::text::font_system().write().expect("Write to font system").load_font(font);
// after
crate::text::font_system()
    .write()
    .unwrap_or_else(std::sync::PoisonError::into_inner)
    .load_font(font);
Defensive patterns

Strategy: validation

Validate before calling

fn looks_like_font(bytes: &[u8]) -> bool {
    if bytes.len() < 4 {
        return false;
    }
    matches!(&bytes[..4], b"OTTO" | b"ttcf" | b"true" | b"wOFF")
        || bytes.starts_with(&[0x00, 0x01, 0x00, 0x00]) // TrueType
}

if !looks_like_font(&font_bytes) {
    return Err(font::Error::InvalidFont); // fail before touching the global font system
}

Prevention

When it happens

Trigger: Loading application fonts (the fonts() list / load_font) after any thread panicked mid-layout while holding the font-system lock; loading fonts lazily from multiple threads once rendering has started.

Common situations: A panic inside a text-rendering worker (malformed font data, cosmic-text edge case) poisons the global, and the next frame or font load kills the app; custom fonts loaded late in the lifecycle instead of before the first draw.

Related errors


AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16). Data as JSON: /api/errors/273ada992db05326. Report an issue: GitHub.