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
- Find the original panic in the text pipeline — this expect is secondary poisoning
- Load all custom fonts at startup, before spawning render/layout work
- Recover from poison instead of panicking: `write().unwrap_or_else(PoisonError::into_inner)`
- 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
- Load all custom fonts at startup, before any thread can hold the font-system lock
- Validate font bytes (magic/version) before passing them to load_font so bad data fails cleanly
- A panic here is always downstream of an earlier text-pipeline panic — find that one first
- Keep font loading single-threaded; the global cosmic-text state makes concurrency fragile
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
- Read from font system
- Write font system
- lock font name cache
- Write application metadata
- Read last palette
AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16).
Data as JSON: /api/errors/273ada992db05326.
Report an issue: GitHub.