stride3d/stride · error · InvalidOperationException

Font ' ' with style ' ' is already registered with path '…

Error message

Font '{fontName}' with style '{style}' is already registered with path '{existing.FilePath}'. Cannot register a different path '{filePath}' for the same font name and style.

What it means

RegisterFont keys fonts by (fontName, style); if that key already maps to a different file path, the method throws InvalidOperationException rather than silently re-pointing the font. Registering the same path again is a no-op (early return), so only genuine conflicts throw.

Solutions

  1. Register each (fontName, style) pair exactly once; guard registration with a checked flag or if (!registeredFonts.ContainsKey(...)) equivalent check
  2. Use a different fontName for the second path if both variants must coexist
  3. Reuse the existing registration (same path is a safe no-op) instead of passing a new path
  4. Catch InvalidOperationException and log it instead of failing startup if re-registration is benign in your app

Example fix

// before
fontProvider.RegisterFont("UI", "assets/UIFont-v2.ttf"); // already registered with v1
// after
if (!fontProvider.IsRegistered("UI", FontStyle.Regular))
    fontProvider.RegisterFont("UI", "assets/UIFont-v2.ttf");
Defensive patterns

Strategy: validation

Validate before calling

if (registered.ContainsKey((fontName, style)) && registered[(fontName, style)] != filePath)
    log.Warn($"Font {fontName}/{style} re-registered with different path; skipping");
else
    fontProvider.RegisterFont(fontName, filePath, style);

Try / catch

try { fontProvider.RegisterFont(name, path, style); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already registered"))
{
    log.Warn($"Ignoring duplicate font registration: {ex.Message}");
}

Prevention

When it happens

Trigger: Calling RegisterFont twice for the same fontName/style with different filePath values, e.g. re-registering after a config change or registering dev and release variants of the same family.

Common situations: Application startup code executed twice (double initialization); switching font file locations between versions without unregistering; two modules each registering their own copy of the same font family/style.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/612530c86eaa6f3c. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Font/RuntimeFontProvider.cs:60

    /// <param name="filePath">The absolute or relative path to the .ttf file.</param>
    /// <param name="style">The font style.</param>
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="fontName"/> is null or empty.</exception>
    /// <exception cref="FileNotFoundException">Thrown when the font file does not exist.</exception>
    /// <exception cref="InvalidOperationException">Thrown when attempting to register the same font name and style with a different file path.</exception>
    public void RegisterFont(string fontName, string filePath, FontStyle style = FontStyle.Regular)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(fontName);

        if (!File.Exists(filePath))
            throw new FileNotFoundException($"Font file not found: {filePath}", filePath);

        var key = FontHelper.GetFontPath(fontName, style);

        if (registeredFonts.TryGetValue(key, out var existing))
        {
            if (existing.FilePath == filePath) return;

            throw new InvalidOperationException(
                $"Font '{fontName}' with style '{style}' is already registered with path '{existing.FilePath}'. " +
                $"Cannot register a different path '{filePath}' for the same font name and style.");
        }

        fontSystem.FontManager.LoadFontFromFileSystem(fontName, filePath, style);

        registeredFonts[key] = new RuntimeFontInfo(fontName, filePath, style);
    }

    /// <summary>
    /// Checks if a font is registered for runtime loading.
    /// </summary>
    /// <param name="fontName">The font name.</param>
    /// <param name="style">The font style.</param>
    /// <returns>True if registered, false otherwise.</returns>
    public bool IsRegistered(string fontName, FontStyle style = FontStyle.Regular)
    {
        return registeredFonts.ContainsKey(FontHelper.GetFontPath(fontName, style));

View on GitHub (pinned to 96fad776d2)