dotnet/wpf · error · ArgumentException

SR.GlyphsClusterNoMatchingBracket

Error message

SR.GlyphsClusterNoMatchingBracket

What it means

Thrown by Glyphs.ReadGlyphIndex while parsing a glyph cluster spec like "[3:2]" in the Glyphs.GlyphIndices string. When an opening bracket '(' was seen, a matching ')' must exist and must leave room for at least one character between the brackets. The parser throws ArgumentException when the closing bracket is missing or directly abuts the opening one.

Solutions

  1. Add the matching ')' and at least one character inside the cluster spec, e.g. ";[3:2]" or "(12:2)".
  2. Validate the GlyphIndices string with a parser or regex before assigning it to Glyphs.GlyphIndices.
  3. Wrap the property assignment in try/catch for ArgumentException to surface a clearer message to the user.

Example fix

// before
glyphs.GlyphIndices = "10;[2;20"; // missing ')'
// after
glyphs.GlyphIndices = "10;[2:2];20";
Defensive patterns

Strategy: validation

Validate before calling

static bool HasBalancedNonEmptyCluster(string indices) => indices == null || indices.Split(';').All(s => !s.Contains('(') || (s.Contains(')') && s.IndexOf(')') > s.IndexOf('(') + 1));
if (!HasBalancedNonEmptyCluster(glyphIndices)) throw new FormatException("Malformed glyph cluster spec");
glyphs.GlyphIndices = glyphIndices;

Type guard

static bool IsValidClusterToken(string token) => !token.Contains('(') || (token.Contains(')') && token.IndexOf(')') > token.IndexOf('(') + 1);

Try / catch

try { glyphs.GlyphIndices = value; }
catch (ArgumentException ex) when (ex.Message.Contains("bracket")) { LogParseFailure(value); throw new FormatException("GlyphIndices cluster spec missing matching bracket", ex); }

Prevention

When it happens

Trigger: Setting Glyphs.GlyphIndices (directly or via ParseGlyphsProperty, e.g. from XAML) with a cluster token containing '(' but no ')', or a token like "()[...]" where secondBracket == firstBracket + 1 (empty cluster spec).

Common situations: Hand-written GlyphIndices strings in XAML with a truncated or typoed cluster section (e.g. ";[2" or ";()"); string generation code that forgot the closing bracket; copy/paste truncation.

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

Appendix: source

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

            // 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);
                    ReadOnlySpan<char> characterClusterSpec = valueSpec.Slice(firstBracket + 1, colon - (firstBracket + 1));
                    characterClusterSize = int.Parse(characterClusterSpec, provider: CultureInfo.InvariantCulture);
                    ReadOnlySpan<char> glyphClusterSpec = valueSpec.Slice(colon + 1, secondBracket - (colon + 1));
                    glyphClusterSize = int.Parse(glyphClusterSpec, provider: CultureInfo.InvariantCulture);

View on GitHub (pinned to 81131a70a4)