dotnet/wpf · error · ArgumentException

SR.GlyphsClusterBadCharactersBeforeBracket

Error message

SR.GlyphsClusterBadCharactersBeforeBracket

What it means

Glyph index specs support cluster syntax '(a,b,c)' inside the Indices string. ParseGlyphsProperty's ReadGlyphIndex requires that only whitespace precede the opening '(' of a cluster; any other character before it throws this ArgumentException.

Solutions

  1. Insert a separator (e.g. ';') or space between the preceding glyph index and the cluster bracket
  2. Ensure cluster groups like '(a,b)' start at the beginning of the spec or after valid separators
  3. Validate the Indices string against the Glyphs cluster grammar

Example fix

// before
Indices="12(3,4)"
// after
Indices="12;(3,4)"
Defensive patterns

Strategy: validation

Validate before calling

int i = indices.IndexOf('(');
bool ok = i <= 0 || indices.Take(i).All(char.IsWhiteSpace);

Try / catch

try { glyphs.Indices = value; } catch (ArgumentException) { /* insert ';' separator before '(' */ }

Prevention

When it happens

Trigger: An Indices value where a cluster opening bracket follows a non-whitespace character, e.g. '12(3,4)' or 'a(1,2)'.

Common situations: Hand-written Indices strings missing the semicolon or comma separator before a cluster; converter output concatenating glyph indexes and clusters without a separator.

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

Appendix: source

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

        /// <returns>true if glyph index is present, false if glyph index is not present.</returns>
        private bool ReadGlyphIndex(
            ReadOnlySpan<char> valueSpec,
            ref bool           inCluster,
            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;
                }

View on GitHub (pinned to 81131a70a4)