slint-ui/slint · critical

fatal: swash is unable to parse truetype font

Error message

fatal: swash is unable to parse truetype font

What it means

In the software renderer's system-font backend, fonts are enumerated by fontique and then converted to swash::FontRef to obtain shaping/cache keys. get_swash_font_info assumes every blob fontique hands over is a well-formed TrueType/OpenType file; if swash::FontRef::from_index cannot parse the data at the given collection index, the code panics with 'fatal: swash is unable to parse truetype font'. The panic happens the first time such a font is needed for shaping, deep inside text layout.

Source

Thrown at internal/renderers/software/fonts/systemfonts.rs:30

use super::super::PhysicalLength;
use super::vectorfont::VectorFont;

struct CachedFontInfo {
    swash_key: swash::CacheKey,
    swash_offset: u32,
}

i_slint_core::thread_local! {
    // swash font info cached and indexed by fontique blob id (unique incremental) and true type collection index
    static SWASH_FONTS: RefCell<HashMap<(HashedBlob, u32), CachedFontInfo>> = Default::default();
}

pub fn get_swash_font_info(blob: &fontique::Blob<u8>, index: u32) -> (swash::CacheKey, u32) {
    SWASH_FONTS.with(|font_cache| {
        let mut cache = font_cache.borrow_mut();
        let info = cache.entry((blob.clone().into(), index)).or_insert_with(move || {
            let font_ref = swash::FontRef::from_index(blob.data(), index as usize)
                .expect("fatal: swash is unable to parse truetype font");
            CachedFontInfo { swash_key: font_ref.key, swash_offset: font_ref.offset }
        });
        (info.swash_key, info.swash_offset)
    })
}

fn get_swash_font_info_for_query_font(font: &fontique::QueryFont) -> (swash::CacheKey, u32) {
    get_swash_font_info(&font.blob, font.index)
}

pub fn match_font(
    request: &super::FontRequest,
    scale_factor: super::ScaleFactor,
    collection: &mut fontique::Collection,
    source_cache: &mut fontique::SourceCache,
) -> Option<VectorFont> {
    if request.family.is_some() {
        let requested_pixel_size: PhysicalLength =

View on GitHub (pinned to 3fd8f2ec03)

Solutions

  1. Find and remove/reinstall the broken font: parse every installed font with fontTools (or fc-scan) and act on the one that fails.
  2. Rebuild the font cache afterwards: fc-cache -r --force.
  3. If the file is app-managed, re-export or re-download the font (e.g. fontTools ttx round-trip) and re-ship it.
  4. As a temporary workaround while fixing the font, switch to a renderer that uses a different font stack (renderer-femtovg or renderer-skia).

Example fix

# before: panic 'fatal: swash is unable to parse truetype font' on first text draw
python3 - <<'EOF'
# after: identify the exact broken font, then remove or reinstall it
from fontTools.ttLib import TTFont, TTLibError
import pathlib
for p in pathlib.Path('/usr/share/fonts').rglob('*'):
    if p.suffix.lower() in {'.ttf', '.otf', '.ttc'}:
        try:
            TTFont(str(p))
        except (TTLibError, Exception) as e:
            print('BROKEN FONT - remove or reinstall:', p, e)
EOF
Defensive patterns

Strategy: validation

Validate before calling

# Validate every font the app will enumerate BEFORE first text draw:
from fontTools.ttLib import TTFont
import pathlib

def fonts_ok() -> bool:
    for p in pathlib.Path('/usr/share/fonts').rglob('*'):
        if p.suffix.lower() in {'.ttf', '.otf', '.ttc'}:
            try:
                TTFont(str(p))
            except Exception:
                return False
    return True

assert fonts_ok(), 'unparseable system font present - software renderer will panic'

Try / catch

// The panic is inside text layout; contain it only to keep a headless
// service alive, then fix the font set and restart:
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    slint::run_event_loop_until_quit()
}));
if r.is_err() {
    // dump installed fonts, remove the unparseable one, restart
}

Prevention

When it happens

Trigger: Rendering any text with the software renderer (renderer-software / SLINT_BACKEND with software, or embedded targets using systemfonts) while at least one installed system font is corrupt, truncated, zero-byte, or is a collection whose entry at the reported index cannot be parsed by swash.

Common situations: A partially downloaded or disk-corrupted font in ~/.fonts or /usr/share/fonts; container/OS images shipping a malformed .ttc; stale fontconfig cache pointing at a replaced file; exotic or quasi-OpenType fonts that one parser accepts and swash rejects.

Understand the failure class

Related errors


AI-assisted analysis of slint-ui/slint@3fd8f2ec03 (2026-08-19). Data as JSON: /api/errors/0138368d8246d3f9. Report an issue: GitHub.