iced-rs/iced · error

Write font system

Error message

Write font system

What it means

iced keeps one global cosmic-text FontSystem behind a std::sync::RwLock (text::font_system() in graphics/src/text.rs:119). Every Editor mutation, including perform (editor.rs:313), takes the write lock with .write().expect("Write font system"). That expect only fails when the lock is poisoned, i.e. some thread panicked earlier while holding this lock; this panic is fallout, and the root cause is the first panic inside a font-system critical section.

Solutions

  1. Find and fix the FIRST panic: rerun with RUST_BACKTRACE=1; this expect's backtrace only shows the victim, so reproduce the earlier failure
  2. If you drive text APIs on your own threads, wrap them in catch_unwind and shut down on Err instead of poisoning the global for the UI thread
  3. Restart the process: a poisoned static RwLock cannot be unpoisoned in place
  4. Upgrade iced: font-system and cosmic-text panics have been fixed across releases

Example fix

// before - background thread can poison the global font system
std::thread::spawn(|| { editor.perform(action); });

// after - isolate panics so the global lock never gets poisoned
let ok = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    editor.perform(action)
}));
if ok.is_err() {
    std::process::abort(); // fail fast instead of poisoning every later text call
}
Defensive patterns

Strategy: validation

Validate before calling

// with a direct iced_graphics dependency
if iced_graphics::text::font_system().is_poisoned() {
    // an earlier panic poisoned the global: fail fast with a clear message
    return Err("font system poisoned by an earlier panic".into());
}

Try / catch

let ok = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    editor.perform(action)
}));
if ok.is_err() {
    // do not keep running: every later text call will hit the poisoned lock
    std::process::abort();
}

Prevention

When it happens

Trigger: An earlier panic while the font-system lock was held (a cosmic-text shaping panic, a panic in custom code running under the lock, or another iced text API that panicked), after which every Editor::perform dies with this message when it takes the lock.

Common situations: Background threads doing text work; apps that swallowed a first panic with catch_unwind and kept running; font loading problems (missing/malformed fonts) that panicked during shaping.

Related errors


AI-assisted analysis of iced-rs/iced@3de451447b (2026-08-17). Data as JSON: /api/errors/c995ce2e29ff6ca5. Report an issue: GitHub.

Appendix: source

Thrown at graphics/src/text/editor.rs:313

        let selection = match editor.selection() {
            cosmic_text::Selection::None => None,
            cosmic_text::Selection::Normal(cursor)
            | cosmic_text::Selection::Line(cursor)
            | cosmic_text::Selection::Word(cursor) => Some(Position {
                line: cursor.line,
                index: cursor.index,
            }),
        };

        Cursor {
            position,
            selection,
        }
    }

    fn perform(&mut self, action: Action) {
        let mut font_system = text::font_system().write().expect("Write font system");

        self.with_internal_mut(|internal| {
            let editor = &mut internal.editor;

            match action {
                // Motion events
                Action::Move(motion) => {
                    if let Some((start, end)) = editor.selection_bounds() {
                        editor.set_selection(cosmic_text::Selection::None);

                        match motion {
                            // These motions are performed as-is even when a selection
                            // is present
                            Motion::Home
                            | Motion::End
                            | Motion::DocumentStart
                            | Motion::DocumentEnd => {
                                editor.action(

View on GitHub (pinned to 3de451447b)