dotnet/wpf · error · ArgumentException

SR.CollectionNumberOfElementsMustBeLessOrEqualTo

Error message

SR.CollectionNumberOfElementsMustBeLessOrEqualTo

What it means

GlyphTypeface.ComputeSubset throws ArgumentException with SR.CollectionNumberOfElementsMustBeLessOrEqualTo when the glyphs collection has more than ushort.MaxValue (65535) elements. Glyph indices in TrueType fonts are 16-bit, so the subset request cannot exceed 65535 entries; larger requests are rejected before any font parsing occurs.

Solutions

  1. Deduplicate the glyph index collection (Distinct()) before calling ComputeSubset
  2. Cap the collection at 65535 entries; if more glyphs are genuinely needed, skip subsetting and embed the full font
  3. Build the glyph set from distinct characters via CharacterToGlyphMap instead of per-occurrence mapping

Example fix

// before
glyphTypeface.ComputeSubset(outStream, allGlyphs);
// after
var unique = allGlyphs.Distinct().Take(ushort.MaxValue).ToArray();
glyphTypeface.ComputeSubset(outStream, unique);
Defensive patterns

Strategy: validation

Validate before calling

var uniqueGlyphs = glyphs.Distinct().Take(ushort.MaxValue).ToArray();
if (uniqueGlyphs.Length < glyphs.Count)
    log.Warn($"Glyph set reduced from {glyphs.Count} to {uniqueGlyphs.Length}");

glyphTypeface.ComputeSubset(outStream, uniqueGlyphs);

Try / catch

try { glyphTypeface.ComputeSubset(outStream, glyphs); }
catch (ArgumentException ex) when (ex.ParamName == "glyphs")
{
    log.Warn("Subset skipped: glyph count exceeds 65535; falling back to full font", ex);
    CopyFullFont(outStream);
}

Prevention

When it happens

Trigger: Calling ComputeSubset with ICollection<ushort>.Count > 65535 — e.g. passing every glyph index in a range without deduplication, or appending indices for each character occurrence instead of each unique glyph.

Common situations: Subsetting a large CJK font by iterating all characters in a document and adding a glyph per character occurrence rather than per distinct glyph; a font with the full 65536 glyph space enumerated wholesale.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

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

        /// </summary>
        /// <param name="glyphs">Collection of glyph indices to be included into the subset.</param>
        /// <returns>Binary image of font subset.</returns>
        /// <remarks>
        ///     Callers must have UnmanagedCode permission to call this API.
        ///     Callers must have FileIOPermission or WebPermission to font location to call this API.
        /// </remarks>
        [CLSCompliant(false)]
        public byte[] ComputeSubset(ICollection<ushort> glyphs)
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphTypeface

            ArgumentNullException.ThrowIfNull(glyphs);

            if (glyphs.Count <= 0)
                throw new ArgumentException(SR.CollectionNumberOfElementsMustBeGreaterThanZero, nameof(glyphs));

            if (glyphs.Count > ushort.MaxValue)
                throw new ArgumentException(SR.Format(SR.CollectionNumberOfElementsMustBeLessOrEqualTo, ushort.MaxValue), nameof(glyphs));

            UnmanagedMemoryStream pinnedFontSource = FontSource.GetUnmanagedStream();

            try
            {
                TrueTypeFontDriver trueTypeDriver = new TrueTypeFontDriver(pinnedFontSource, _originalUri);
                trueTypeDriver.SetFace(FaceIndex);

                return trueTypeDriver.ComputeFontSubset(glyphs);
            }
            catch (SEHException e)
            {
                throw Util.ConvertInPageException(FontSource, e);
            }
            finally
            {
                pinnedFontSource.Close();
            }

View on GitHub (pinned to 81131a70a4)