dotnet/wpf · error · ArgumentOutOfRangeException

SR.GlyphIndexOutOfRange

Error message

SR.GlyphIndexOutOfRange

What it means

The GlyphMetrics helper throws ArgumentOutOfRangeException with SR.GlyphIndexOutOfRange when the supplied glyphIndex is greater than or equal to the font's GlyphCount as reported by DirectWrite. Glyph indices are font-specific and bounded by the font's glyph table size; querying metrics, sidebearings, or advance geometry for an out-of-bounds index would access undefined data.

Solutions

  1. Verify glyphIndex < GlyphTypeface... glyph count before calling; expose the count via the underlying FontFace GlyphCount and guard the call
  2. Obtain glyph indices from the same GlyphTypeface instance via its CharacterToGlyphMap, never across different faces
  3. Reset/recompute cached glyph indices whenever the font face changes
  4. Catch ArgumentOutOfRangeException around metric queries and treat them as missing-glyph cases

Example fix

// before
var metrics = glyphTypeface.GlyphMetrics(glyphIndex, textFormattingMode, pixelsPerDip);
// after
if (glyphIndex < fontFaceGlyphCount)
    var metrics = glyphTypeface.GlyphMetrics(glyphIndex, textFormattingMode, pixelsPerDip);
else
    /* treat as missing glyph / use 0 index */;
Defensive patterns

Strategy: validation

Validate before calling

bool IsValidGlyphIndex(GlyphTypeface face, ushort glyphIndex)
{
    // DirectWrite bounds: must be < GlyphCount of the underlying font face
    return glyphIndex < face.CharToFriendlyGlyphNameMap.Count; // or cache face's GlyphCount via _font.GetFontFace().GlyphCount
}

Type guard

static bool IsInGlyphRange(ushort glyphIndex, ushort glyphCount) => glyphIndex < glyphCount;

Try / catch

try
{
    var metrics = glyphTypeface.GlyphMetrics(glyphIndex, mode, pixelsPerDip);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "glyphIndex")
{
    // treat as missing glyph: fall back to index 0 (.notdef)
    var metrics = glyphTypeface.GlyphMetrics(0, mode, pixelsPerDip);
}

Prevention

When it happens

Trigger: Calling glyphMetrics, GetLeftSidebearing, GetRightSidebearing, GetTopSidebearing, or GetBottomSidebearing with a glyphIndex that came from a different font, from an unvalidated CharacterToGlyphMap miss, or from hardcoded assumptions about glyph numbering.

Common situations: Reusing cached glyph indices after switching the GlyphTypeface/font family; mapping a character to a glyph in one font and using the index against another font; fonts loaded via font fallback where indices differ per face; corrupted CharacterToGlyphMap lookups returning sentinel values.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/82110cd359683eac. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphTypeface.cs:1061

                out bsb,
                out baseline
            );
            return ah;
        }

        private unsafe MS.Internal.Text.TextInterface.GlyphMetrics GlyphMetrics(ushort             glyphIndex,
                                                                                double             emSize,
                                                                                float              pixelsPerDip,
                                                                                TextFormattingMode textFormattingMode,
                                                                                bool               isSideways)
        {
            MS.Internal.Text.TextInterface.GlyphMetrics glyphMetrics;

            MS.Internal.Text.TextInterface.FontFace fontFaceDWrite = _font.GetFontFace();
            try
            {
                if (glyphIndex >= fontFaceDWrite.GlyphCount)
                    throw new ArgumentOutOfRangeException(nameof(glyphIndex), SR.Format(SR.GlyphIndexOutOfRange, glyphIndex));

                glyphMetrics = new MS.Internal.Text.TextInterface.GlyphMetrics();

                if (textFormattingMode == TextFormattingMode.Ideal)
                {
                    // We can safely pass pointers to glyphIndex and glyphMetrics since both are value types and are allocated on the stack.
                    fontFaceDWrite.GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics);
                }
                else
                {
                    // We can safely pass pointers to glyphIndex and glyphMetrics since both are value types and are allocated on the stack.
                    fontFaceDWrite.GetDisplayGlyphMetrics(&glyphIndex, 1, &glyphMetrics, checked((float)emSize),
                        textFormattingMode != TextFormattingMode.Display, isSideways, pixelsPerDip);
                }
            }
            finally
            {
                fontFaceDWrite.Release();

View on GitHub (pinned to 81131a70a4)