dotnet/wpf · error · ArgumentException

SR.GlyphsClusterNoNestedClusters

Error message

SR.GlyphsClusterNoNestedClusters

What it means

Fired from ReadGlyphIndex while parsing the Glyphs UnicodeString/Indices mini-language: a cluster specification of the form (CharacterClusterSize[:GlyphClusterSize]) was encountered while already parsing a cluster (nested '(' inside the bracketed section). Cluster specs cannot nest, so the parser rejects the malformed Indices string.

Solutions

  1. Remove nested brackets so clusters are flat, e.g. '(1,2,3)'
  2. Close every cluster with ')' before starting a new one
  3. Validate that '(' never appears twice without an intervening ')'

Example fix

// before
Indices="(1,(2,3))"
// after
Indices="(1,2,3)"
Defensive patterns

Strategy: validation

Validate before calling

int depth = 0;
bool ok = indices.All(c => { if (c=='(') depth++; else if (c==')') depth--; return depth <= 1; });

Try / catch

try { glyphs.Indices = value; } catch (ArgumentException) { /* flatten nested clusters */ }

Prevention

When it happens

Trigger: Indices strings with nested brackets such as '(1,(2,3))' or an unclosed cluster followed by another '(' character.

Common situations: Malformed Indices from manual editing or buggy generators producing nested cluster groups; typos leaving a cluster unbalanced.

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/dc86e0d51094bc72. Report an issue: GitHub.

Appendix: source

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

            ref int            glyphClusterSize,
            ref int            characterClusterSize,
            ref ushort         glyphIndex)
        {
            // the format is ... [(CharacterClusterSize[:GlyphClusterSize])] GlyphIndex ...
            ReadOnlySpan<char> glyphIndexString = valueSpec;

            int firstBracket = valueSpec.IndexOf('(');
            if (firstBracket != -1)
            {
                // Only spaces are allowed before the bracket
                for (int i=0; i<firstBracket; i++)
                {
                    if (!Char.IsWhiteSpace(valueSpec[i]))
                        throw new ArgumentException(SR.GlyphsClusterBadCharactersBeforeBracket);
                }

                if (inCluster)
                    throw new ArgumentException(SR.GlyphsClusterNoNestedClusters);

                int secondBracket = valueSpec.IndexOf(')');
                if (secondBracket == -1 || secondBracket <= firstBracket + 1)
                    throw new ArgumentException(SR.GlyphsClusterNoMatchingBracket);

                // look for colon separator
                int colon = valueSpec.IndexOf(':');
                if (colon == -1)
                {
                    // parse glyph cluster size
                    ReadOnlySpan<char> characterClusterSpec = valueSpec.Slice(firstBracket + 1, secondBracket - (firstBracket + 1));
                    characterClusterSize = int.Parse(characterClusterSpec, provider: CultureInfo.InvariantCulture);
                    glyphClusterSize = 1;
                }
                else
                {
                    if (colon <= firstBracket + 1 || colon >= secondBracket - 1)
                        throw new ArgumentException(SR.GlyphsClusterMisplacedSeparator);

View on GitHub (pinned to 81131a70a4)