stride3d/stride · error · InvalidOperationException
Failed to load font from
Error message
Failed to load font from '{filePath}' (FreeType error {err}) What it means
LoadFontFromFileSystem reads the font file into memory and asks FreeType to parse it via FT_New_Memory_Face. A nonzero error means FreeType could not parse the data as a supported font format, so an InvalidOperationException is thrown with the file path and FreeType error code.
Solutions
- Validate the file is a real TrueType/OpenType font (check magic bytes 0x00010000 / 'OTTO') before loading
- Re-copy the font file from a known-good source; check file size > 0
- Decode the FreeType error code in the message (e.g. 2 = cannot open resource, 3 = unknown file format) to target the fix
- Ensure the deployment pipeline copies font files verbatim (no encoding/line-ending transforms)
Example fix
// before
fontManager.LoadFontFromFileSystem(name, suspiciousPath, style);
// after
var bytes = File.ReadAllBytes(suspiciousPath);
if (bytes.Length < 12)
throw new InvalidDataException($"Font file too small or corrupt: {suspiciousPath}");
fontManager.LoadFontFromFileSystem(name, suspiciousPath, style); Defensive patterns
Strategy: validation
Validate before calling
var data = File.ReadAllBytes(filePath);
if (data.Length < 12) throw new InvalidDataException($"Not a font file: {filePath}");
bool validMagic = data[0]==0 && data[1]==1 && data[2]==0 && data[3]==0
|| data[0]==(byte)'O' && data[1]==(byte)'T' && data[2]==(byte)'T' && data[3]==(byte)'O'; Try / catch
try { fontManager.LoadFontFromFileSystem(name, path, style); }
catch (InvalidOperationException ex) when (ex.Message.Contains("FreeType error"))
{
log.Error($"Font load failed for {path}; falling back to default font", ex);
LoadDefaultFont();
} Prevention
- Verify font files load in a tool (e.g. fontconfig) before shipping
- Ship fonts as binary content; disable any transform that could corrupt them
- Log and map FreeType error codes for faster diagnosis
When it happens
Trigger: Calling LoadFontFromFileSystem with a file that exists but is not a valid font (corrupted download, truncated file, wrong extension, unsupported format like a bitmap-only font).
Common situations: Deploying a placeholder/zero-byte .ttf; fonts corrupted by source-control line-ending mangling or incomplete copy; pointing at an HTML error page saved as .ttf; font format not compiled into the shipped FreeType build.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to initialize FreeType library
- Failed to initialize FreeType library
- Failed to load font ' ' (FreeType error )
- Block compression requires texture size to be a multiple of…
- character
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/25e4fc1cb11ca87d.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/Font/FontManager.cs:162
public void LoadFontFromFileSystem(string fontName, string filePath, FontStyle style)
{
var cacheKey = FontHelper.GetFontPath(fontName, style);
lock (freetypeLock)
{
if (cachedFontFaces.ContainsKey(cacheKey))
return;
var fontData = File.ReadAllBytes(filePath);
var handle = GCHandle.Alloc(fontData, GCHandleType.Pinned);
fixed (byte* ptr = fontData)
{
int err = FreeTypeNative.FT_New_Memory_Face(freetypeLibrary, ptr, new CLong(fontData.Length), new CLong(0), out FT_FaceRec* face);
if (err != 0)
{
handle.Free();
throw new InvalidOperationException($"Failed to load font from '{filePath}' (FreeType error {err})");
}
cachedFontFaces[cacheKey] = ((nint)face, handle);
}
}
}
private void GenerateCharacterGlyph(CharacterSpecification character, bool renderBitmap, bool computeMetrics)
{
// Reset and (re)compute Glyph.XAdvance only on the metric pass. The async builder thread
// re-renders the bitmap of an already-measured glyph and must leave XAdvance untouched:
// text measurement reads it lock-free while the bitmap is still pending, so zeroing it
// here — even transiently — makes the last glyph on a line measure as zero-width and the
// UI background fall short of the text.
if (computeMetrics)
ResetGlyph(character);
// let the glyph info null if the size is not valid
if (character.Size.X < 1 || character.Size.Y < 1)View on GitHub (pinned to 96fad776d2)