{"record":{"id":"f34c6883c3c08d9f","repo":"stride3d/stride","slug":"failed-to-load-font-fontsource-freetype-error-err","errorCode":null,"errorMessage":"Failed to load font '{fontSource}' (FreeType error {err})","messagePattern":"Failed to load font '(.+?)' \\(FreeType error (.+?)\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Assets/SpriteFont/Compiler/SignedDistanceFieldFontImporter.cs","lineNumber":79,"sourceCode":"                MsdfgenNative.msdfgenContextDestroy(msdfgenContext);\n                msdfgenContext = IntPtr.Zero;\n                FreeTypeNative.FT_Done_FreeType(library);\n                throw new AssetException($\"Failed to load font '{fontSource}' into msdfgen.\");\n            }\n\n            try\n            {\n                var fontData = File.ReadAllBytes(fontSource);\n                var handle = GCHandle.Alloc(fontData, GCHandleType.Pinned);\n\n                try\n                {\n                    FT_FaceRec* face;\n                    fixed (byte* ptr = fontData)\n                    {\n                        err = FreeTypeNative.FT_New_Memory_Face(library, ptr, new CLong(fontData.Length), new CLong(0), out face);\n                        if (err != 0)\n                            throw new InvalidOperationException($\"Failed to load font '{fontSource}' (FreeType error {err})\");\n                    }\n\n                    try\n                    {\n                        var fontSize = options.FontType.Size;\n\n                        // FreeType metrics are in font units; convert to pixels\n                        float unitsToPixels = fontSize / face->units_per_EM;\n\n                        var lineGap = (face->height - face->ascender + face->descender) * options.LineGapFactor;\n                        LineSpacing = (lineGap + face->ascender - face->descender) * unitsToPixels;\n                        BaseLine = (lineGap * options.LineGapBaseLineFactor + face->ascender) * unitsToPixels;\n\n                        var glyphList = new List<Glyph>();\n                        foreach (var character in characters)\n                            glyphList.Add(ImportGlyph(character, fontSize));\n\n                        Glyphs = glyphList;","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Assets/SpriteFont/Compiler/SignedDistanceFieldFontImporter.cs#L61-L97","documentation":"After msdfgen loads the font, the importer reads the font bytes and asks FreeType (FT_New_Memory_Face) to create a face from memory; a non-zero FreeType error code means FreeType rejected the font data. The error message embeds the raw FreeType error code. This is a font-file validity problem detected by FreeType.","triggerScenarios":"Compiling an SDF spritefont where FT_New_Memory_Face returns an error such as 2 (Cannot Open Resource), 3 (Unknown File Format), or 85 (invalid table) for the bytes at fontSource.","commonSituations":"Font file truncated during version control or copy (LFS not pulled); actually a WOFF/WOFF2 or bitmap-only font renamed to .ttf; corrupted download; empty file committed accidentally.","solutions":["Decode the FreeType code (e.g. 2 = cannot open resource, 3 = unknown file format) to identify the issue.","Validate the font with `ftdump`/`fonttools ttx` or a font viewer and replace it with a valid TTF/OTF.","Check file size on disk vs. expected; ensure Git LFS files are checked out fully.","Convert WOFF2 fonts to TTF before using them as FontSource."],"exampleFix":"// before\nFontSource = \"fonts/MyFont.woff2\", // FreeType error 3 (unknown format)\n// after\nFontSource = \"fonts/MyFont.ttf\", // converted with woff2_decompress / fonttools","handlingStrategy":"validation","validationCode":"byte[] data = File.ReadAllBytes(fontPath.ToOSPath());\n// TTF: 0x00010000 or 'true'; OTF/CFF: 'OTTO'\nbool looksLikeFont = data.Length > 12 &&\n    (BitConverter.ToUInt32(data, 0) == 0x00010000 ||\n     data[0] == 'O' && data[1] == 'T' && data[2] == 'T' && data[3] == 'O');\nif (!looksLikeFont) throw new InvalidDataException($\"{fontPath} is not a TTF/OTF file\");","typeGuard":"static bool IsTrueTypeOrOpenType(byte[] d) => d.Length >= 4 &&\n    (d[0] == 0x00 && d[1] == 0x01) || (d[0] == 'O' && d[1] == 'T' && d[2] == 'T' && d[3] == 'O');","tryCatchPattern":"try\n{\n    CompileSdfFont(asset);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"FreeType error\"))\n{\n    logger.Error($\"FreeType rejected '{asset.FontSource}': {ex.Message}. Re-export as TTF/OTF.\");\n}","preventionTips":["Never rename WOFF/WOFF2 to .ttf; convert formats explicitly","Track fonts with Git LFS and verify checkouts are complete","Run a font-validation step in CI before asset compilation"],"tags":["asset-compiler","font","freetype","native-interop"],"backgroundTag":"invalid-argument-value","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}