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
- Add the matching ')' and at least one character inside the cluster spec, e.g. ";[3:2]" or "(12:2)".
- Validate the GlyphIndices string with a parser or regex before assigning it to Glyphs.GlyphIndices.
- 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
- Always emit clusters as '(n:m)' with both brackets present
- Unit-test GlyphIndices strings through a parser before shipping generated output
- Never hand-edit cluster sections without checking bracket pairing
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
- SR.GlyphsClusterMisplacedSeparator
- SR.GlyphsIndexRequiredIfNoUnicode
- SR.GlyphsIndexRequiredWithinCluster
- SR.GlyphsTooManyCommas
- MappingParseError(_scanner.Start, MappingScanner.Ident…
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)