stride3d/stride · error · InvalidOperationException
Failed to load font ' ' (FreeType error )
Error message
Failed to load font '{fontSource}' (FreeType error {err}) What it means
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.
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.
Example fix
// before FontSource = "fonts/MyFont.woff2", // FreeType error 3 (unknown format) // after FontSource = "fonts/MyFont.ttf", // converted with woff2_decompress / fonttools
Defensive patterns
Strategy: validation
Validate before calling
byte[] data = File.ReadAllBytes(fontPath.ToOSPath());
// TTF: 0x00010000 or 'true'; OTF/CFF: 'OTTO'
bool looksLikeFont = data.Length > 12 &&
(BitConverter.ToUInt32(data, 0) == 0x00010000 ||
data[0] == 'O' && data[1] == 'T' && data[2] == 'T' && data[3] == 'O');
if (!looksLikeFont) throw new InvalidDataException($"{fontPath} is not a TTF/OTF file"); Type guard
static bool IsTrueTypeOrOpenType(byte[] d) => d.Length >= 4 &&
(d[0] == 0x00 && d[1] == 0x01) || (d[0] == 'O' && d[1] == 'T' && d[2] == 'T' && d[3] == 'O'); Try / catch
try
{
CompileSdfFont(asset);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("FreeType error"))
{
logger.Error($"FreeType rejected '{asset.FontSource}': {ex.Message}. Re-export as TTF/OTF.");
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Failed to load font ' ' into msdfgen.
- Could not locate native executable
- Could not locate native library
- Failed to initialize FreeType library
- Failed to load font ' ' (FreeType error )
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/f34c6883c3c08d9f.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Assets/SpriteFont/Compiler/SignedDistanceFieldFontImporter.cs:79
MsdfgenNative.msdfgenContextDestroy(msdfgenContext);
msdfgenContext = IntPtr.Zero;
FreeTypeNative.FT_Done_FreeType(library);
throw new AssetException($"Failed to load font '{fontSource}' into msdfgen.");
}
try
{
var fontData = File.ReadAllBytes(fontSource);
var handle = GCHandle.Alloc(fontData, GCHandleType.Pinned);
try
{
FT_FaceRec* face;
fixed (byte* ptr = fontData)
{
err = FreeTypeNative.FT_New_Memory_Face(library, ptr, new CLong(fontData.Length), new CLong(0), out face);
if (err != 0)
throw new InvalidOperationException($"Failed to load font '{fontSource}' (FreeType error {err})");
}
try
{
var fontSize = options.FontType.Size;
// FreeType metrics are in font units; convert to pixels
float unitsToPixels = fontSize / face->units_per_EM;
var lineGap = (face->height - face->ascender + face->descender) * options.LineGapFactor;
LineSpacing = (lineGap + face->ascender - face->descender) * unitsToPixels;
BaseLine = (lineGap * options.LineGapBaseLineFactor + face->ascender) * unitsToPixels;
var glyphList = new List<Glyph>();
foreach (var character in characters)
glyphList.Add(ImportGlyph(character, fontSize));
Glyphs = glyphList;View on GitHub (pinned to 96fad776d2)