{"record":{"id":"4472cdb77304f25a","repo":"AvaloniaUI/Avalonia","slug":"no-suitable-cmap-subtable-found","errorCode":null,"errorMessage":"No suitable cmap subtable found.","messagePattern":"No suitable cmap subtable found\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/Fonts/Tables/Cmap/CmapTable.cs","lineNumber":70,"sourceCode":"            if (TryFindFormat12Or13Entry(entries, CmapFormat.Format12, out var format12Entry))\n            {\n                // Prefer Format 12 if available\n                return new CharacterToGlyphMap(new CmapFormat12Or13Table(format12Entry.GetSubtableMemory(table)));\n            }\n\n            // Then Format 4\n            if (TryFindFormat4Entry(entries, out var format4Entry))\n            {\n                return new CharacterToGlyphMap(new CmapFormat4Table(format4Entry.GetSubtableMemory(table)));\n            }\n\n            // Fallback to Format 13, which is a \"last resort\" format mapping many codepoints to a single glyph\n            if (TryFindFormat12Or13Entry(entries, CmapFormat.Format13, out var format13Entry))\n            {\n                return new CharacterToGlyphMap(new CmapFormat12Or13Table(format13Entry.GetSubtableMemory(table)));\n            }\n\n            throw new InvalidOperationException(\"No suitable cmap subtable found.\");\n\n            // Tries to find the best Format 12 subtable entry based on platform and encoding preferences\n            static bool TryFindFormat12Or13Entry(CmapSubtableEntry[] entries, CmapFormat expectedFormat, out CmapSubtableEntry result)\n            {\n                result = default;\n                var foundPlatformScore = int.MaxValue;\n                var foundEncodingScore = int.MaxValue;\n\n                foreach (var entry in entries)\n                {\n                    if (entry.Format != expectedFormat)\n                    {\n                        continue;\n                    }\n\n                    var platformScore = entry.Platform switch\n                    {\n                        PlatformID.Unicode => 0,","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/Fonts/Tables/Cmap/CmapTable.cs#L52-L88","documentation":"A TrueType/OpenType font's 'cmap' table maps Unicode codepoints to glyph indices; without one, text cannot be rendered. GlyphTypeface.LoadCmap walks the table looking for Format 4 (BMP), then Format 13 (last-resort single-glyph), and if neither platform/encoding combination it prefers is present, it gives up. The exception signals the font is structurally valid but lacks any cmap subtable the engine can use.","triggerScenarios":"Calling GlyphTypeface on a font file whose cmap only contains Format 0, 1, 2, 6, or other unsupported encodings; a font with cmap entries whose platformID/encodingID do not match the preferred Windows/Unicode scores; a corrupt font whose cmap subtables fail to parse so the filter loop yields nothing.","commonSituations":"Shipping a legacy Mac-only TrueType font (platformID 1 only); embedding a hand-crafted or stripped font where the toolchain dropped the Unicode BMP (3,1) subtable; reading a CFF/CFF2 OTF that only declares a Format 12 (3,10) subtable but the loop's platform/encoding scoring rejects it; loading a non-font file as a font.","solutions":["Validate the font with a tool (fontTools 'ttx -l', FontForge, or Microsoft Font Validator) and confirm it has a Format 4 subtable with platformID=3/encodingID=1 or a Format 12/13 subtable.","Re-export or subset the font ensuring a Unicode BMP (3,1) Format 4 cmap subtable is included.","Substitute a known-good system font (e.g. an installed Segoe UI / DejaVu Sans) to confirm the GlyphTypeface pipeline works, then bisect back to the failing asset.","If loading untrusted user fonts, catch InvalidOperationException around GlyphTypeface construction and report the asset path rather than crashing."],"exampleFix":"// before\nvar typeface = new GlyphTypeface(new Uri(assetUri));\n\n// after\nGlyphTypeface typeface;\ntry { typeface = new GlyphTypeface(new Uri(assetUri)); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"cmap\"))\n{\n    typeface = new GlyphTypeface(_fallbackSystemFontUri);\n    _logger.LogWarning(\"Asset {Uri} has no usable cmap; falling back. {Err}\", assetUri, ex.Message);\n}","handlingStrategy":"fallback","validationCode":"static bool HasUsableCmap(string fontPath)\n{\n    try { using var gt = new GlyphTypeface(new Uri(fontPath)); return gt.GlyphCount > 0; }\n    catch (InvalidOperationException) { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { _typeface = new GlyphTypeface(uri); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"cmap\"))\n{\n    _typeface = new GlyphTypeface(_systemFallbackUri);\n    Log.AssetFontIncompatible(uri, ex.Message);\n}","preventionTips":["Validate third-party font assets with Font Validator or fontTools before shipping.","Keep a guaranteed-good system font as a fallback GlyphTypeface source.","Treat any user-uploaded font as untrusted: probe with GlyphCount before use."],"tags":["fonts","font-parsing","cmap","glyph-typeface","asset-validation"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}