{"record":{"id":"0138368d8246d3f9","repo":"slint-ui/slint","slug":"fatal-swash-is-unable-to-parse-truetype-font","errorCode":null,"errorMessage":"fatal: swash is unable to parse truetype font","messagePattern":"fatal: swash is unable to parse truetype font","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/renderers/software/fonts/systemfonts.rs","lineNumber":30,"sourceCode":"use super::super::PhysicalLength;\nuse super::vectorfont::VectorFont;\n\nstruct CachedFontInfo {\n    swash_key: swash::CacheKey,\n    swash_offset: u32,\n}\n\ni_slint_core::thread_local! {\n    // swash font info cached and indexed by fontique blob id (unique incremental) and true type collection index\n    static SWASH_FONTS: RefCell<HashMap<(HashedBlob, u32), CachedFontInfo>> = Default::default();\n}\n\npub fn get_swash_font_info(blob: &fontique::Blob<u8>, index: u32) -> (swash::CacheKey, u32) {\n    SWASH_FONTS.with(|font_cache| {\n        let mut cache = font_cache.borrow_mut();\n        let info = cache.entry((blob.clone().into(), index)).or_insert_with(move || {\n            let font_ref = swash::FontRef::from_index(blob.data(), index as usize)\n                .expect(\"fatal: swash is unable to parse truetype font\");\n            CachedFontInfo { swash_key: font_ref.key, swash_offset: font_ref.offset }\n        });\n        (info.swash_key, info.swash_offset)\n    })\n}\n\nfn get_swash_font_info_for_query_font(font: &fontique::QueryFont) -> (swash::CacheKey, u32) {\n    get_swash_font_info(&font.blob, font.index)\n}\n\npub fn match_font(\n    request: &super::FontRequest,\n    scale_factor: super::ScaleFactor,\n    collection: &mut fontique::Collection,\n    source_cache: &mut fontique::SourceCache,\n) -> Option<VectorFont> {\n    if request.family.is_some() {\n        let requested_pixel_size: PhysicalLength =","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/slint-ui/slint/blob/3fd8f2ec03c2aa8a95d5f4b9daa299c7b8bf4016/internal/renderers/software/fonts/systemfonts.rs#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Find and remove/reinstall the broken font: parse every installed font with fontTools (or fc-scan) and act on the one that fails.","Rebuild the font cache afterwards: fc-cache -r --force.","If the file is app-managed, re-export or re-download the font (e.g. fontTools ttx round-trip) and re-ship it.","As a temporary workaround while fixing the font, switch to a renderer that uses a different font stack (renderer-femtovg or renderer-skia)."],"exampleFix":"# before: panic 'fatal: swash is unable to parse truetype font' on first text draw\npython3 - <<'EOF'\n# after: identify the exact broken font, then remove or reinstall it\nfrom fontTools.ttLib import TTFont, TTLibError\nimport pathlib\nfor p in pathlib.Path('/usr/share/fonts').rglob('*'):\n    if p.suffix.lower() in {'.ttf', '.otf', '.ttc'}:\n        try:\n            TTFont(str(p))\n        except (TTLibError, Exception) as e:\n            print('BROKEN FONT - remove or reinstall:', p, e)\nEOF","handlingStrategy":"validation","validationCode":"# Validate every font the app will enumerate BEFORE first text draw:\nfrom fontTools.ttLib import TTFont\nimport pathlib\n\ndef fonts_ok() -> bool:\n    for p in pathlib.Path('/usr/share/fonts').rglob('*'):\n        if p.suffix.lower() in {'.ttf', '.otf', '.ttc'}:\n            try:\n                TTFont(str(p))\n            except Exception:\n                return False\n    return True\n\nassert fonts_ok(), 'unparseable system font present - software renderer will panic'","typeGuard":null,"tryCatchPattern":"// The panic is inside text layout; contain it only to keep a headless\n// service alive, then fix the font set and restart:\nlet r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    slint::run_event_loop_until_quit()\n}));\nif r.is_err() {\n    // dump installed fonts, remove the unparseable one, restart\n}","preventionTips":["Validate shipped/system fonts with fontTools or fc-scan in image-build CI","Do not replace font files while the app runs (fontique caches blobs by id)","Run fc-cache -r --force after font updates","Prefer embedding one known-good font over relying on system enumeration where possible"],"tags":["fonts","swash","software-renderer","panic","fontconfig"],"backgroundTag":"corrupt-font-file","analyzedSha":"3fd8f2ec03c2aa8a95d5f4b9daa299c7b8bf4016","analyzedAt":"2026-08-19T23:23:16.610Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}