dotnet/wpf · error · ArgumentException

SR.GlyphsIndexRequiredWithinCluster

Error message

SR.GlyphsIndexRequiredWithinCluster

What it means

Thrown by Glyphs.ParseGlyphsProperty in the final pass that fills remaining glyph defaults assuming 1:1 character-to-glyph mapping. If the parser is still inside a glyph cluster (inCluster == true) when characters remain in UnicodeString, an explicit glyph index is required for clustered characters — WPF will not guess glyphs inside a cluster — so it throws ArgumentException.

Solutions

  1. Ensure every cluster spec in GlyphIndices is complete and closed, e.g. ";(2:1)".
  2. Provide explicit glyph indices for all characters covered by clusters.
  3. Verify that summed cluster glyph counts match the number of glyph entries in GlyphIndices.

Example fix

<!-- before -->
<Glyphs UnicodeString="abc" GlyphIndices=";(2:1" />
<!-- after -->
<Glyphs UnicodeString="abc" GlyphIndices=";(2:1);10" />
Defensive patterns

Strategy: validation

Validate before calling

static bool ClustersClosed(string indices) { int open = indices.Count(c => c == '('), close = indices.Count(c => c == ')'); return open == close; }
if (!ClustersClosed(glyphIndices)) throw new FormatException("Unterminated glyph cluster");

Type guard

static bool NotEndingInCluster(string indices) { int depth = 0; foreach (char c in indices) { if (c == '(') depth++; if (c == ')') depth--; } return depth <= 0; }

Try / catch

try { glyphs.GlyphIndices = indices; }
catch (ArgumentException ex) when (ex.Message.Contains("cluster")) { indices += ")"; glyphs.GlyphIndices = indices; } // or reject and regenerate

Prevention

When it happens

Trigger: A GlyphIndices string ending inside an unterminated cluster (e.g. ";(2:1" or a cluster whose glyph count doesn't close) while UnicodeString still has unmatched characters, leaving the parser mid-cluster during default filling.

Common situations: Hand-edited GlyphIndices with an unclosed cluster bracket; cluster glyph counts miscounted so the cluster never terminates; truncated Indices strings from code generation.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/Glyphs.cs:661

                            ++parsedCharacterCount;
                        }
                        parsedGlyphCount++;

                        // initalize new per-glyph values
                        valueWithinGlyph = 0; // which value we're on (how many commas have we seen in this glyph)?
                        valueStartIndex = i + 1; // where (what index of Glyphs prop string) did this value start?
                    }
                }
            }
            #endregion

            // fill the remaining glyphs with defaults, assuming 1:1 mapping
            if (unicodeString != null)
            {
                while (parsedCharacterCount < unicodeString.Length)
                {
                    if (inCluster)
                        throw new ArgumentException(SR.GlyphsIndexRequiredWithinCluster);

                    if (unicodeString.Length <= parsedCharacterCount)
                        throw new ArgumentException(SR.GlyphsUnicodeStringIsTooShort);

                    parsedGlyphData.glyphIndex = GetGlyphFromCharacter(fontFace, unicodeString[parsedCharacterCount]);
                    parsedGlyphData.advanceWidth = GetAdvanceWidth(fontFace, parsedGlyphData.glyphIndex, sideways);
                    parsedGlyphs.Add(parsedGlyphData);
                    parsedGlyphData = new ParsedGlyphData();
                    SetClusterMapEntry(clusterMap, parsedCharacterCount, (ushort)parsedGlyphCount);
                    ++parsedCharacterCount;
                    ++parsedGlyphCount;
                }
            }

            // return number of glyphs actually specified
            return parsedGlyphCount;
        }
        #endregion Parsing and GlyphRun creation

View on GitHub (pinned to 81131a70a4)