{"record":{"id":"1d94c26016214c30","repo":"dotnet/wpf","slug":"sr-glyphsclustermisplacedseparator","errorCode":null,"errorMessage":"SR.GlyphsClusterMisplacedSeparator","messagePattern":"SR\\.GlyphsClusterMisplacedSeparator","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/Glyphs.cs","lineNumber":429,"sourceCode":"                    throw new ArgumentException(SR.GlyphsClusterNoNestedClusters);\n\n                int secondBracket = valueSpec.IndexOf(')');\n                if (secondBracket == -1 || secondBracket <= firstBracket + 1)\n                    throw new ArgumentException(SR.GlyphsClusterNoMatchingBracket);\n\n                // look for colon separator\n                int colon = valueSpec.IndexOf(':');\n                if (colon == -1)\n                {\n                    // parse glyph cluster size\n                    ReadOnlySpan<char> characterClusterSpec = valueSpec.Slice(firstBracket + 1, secondBracket - (firstBracket + 1));\n                    characterClusterSize = int.Parse(characterClusterSpec, provider: CultureInfo.InvariantCulture);\n                    glyphClusterSize = 1;\n                }\n                else\n                {\n                    if (colon <= firstBracket + 1 || colon >= secondBracket - 1)\n                        throw new ArgumentException(SR.GlyphsClusterMisplacedSeparator);\n                    ReadOnlySpan<char> characterClusterSpec = valueSpec.Slice(firstBracket + 1, colon - (firstBracket + 1));\n                    characterClusterSize = int.Parse(characterClusterSpec, provider: CultureInfo.InvariantCulture);\n                    ReadOnlySpan<char> glyphClusterSpec = valueSpec.Slice(colon + 1, secondBracket - (colon + 1));\n                    glyphClusterSize = int.Parse(glyphClusterSpec, provider: CultureInfo.InvariantCulture);\n                }\n                inCluster = true;\n                glyphIndexString = valueSpec.Slice(secondBracket + 1);\n            }\n            if (IsEmpty(glyphIndexString))\n                return false;\n\n            glyphIndex = ushort.Parse(glyphIndexString, provider: CultureInfo.InvariantCulture);\n            return true;\n        }\n\n        private static double GetAdvanceWidth(GlyphTypeface glyphTypeface, ushort glyphIndex, bool sideways)\n        {\n            double advance = sideways ? glyphTypeface.AdvanceHeights[glyphIndex] : glyphTypeface.AdvanceWidths[glyphIndex];","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/Glyphs.cs#L411-L447","documentation":"Thrown by Glyphs.ReadGlyphIndex when a cluster spec \"(chars:glyphs)\" contains a ':' but it is misplaced — immediately after the opening bracket or immediately before the closing bracket — leaving an empty character- or glyph-cluster-size on one side of the colon. Both sides must be non-empty integers.","triggerScenarios":"A GlyphIndices cluster token like \"(;2)\", \"(2;)\", or \";[:2]\" / \";[2:]\" where the colon is at position firstBracket+1 or secondBracket-1.","commonSituations":"Typos when hand-authoring GlyphIndices in XAML (empty side of the colon); generator code emitting empty cluster components for default values instead of omitting the colon.","solutions":["Provide a non-empty integer on both sides of the colon, e.g. \";[2:1]\" for 2 characters mapped to 1 glyph.","If one of the sizes is 1, consider whether you still need the cluster form at all; a plain glyph index may suffice.","Pre-validate the token format (non-empty parts around ':') before assigning GlyphIndices."],"exampleFix":"// before\nglyphs.GlyphIndices = \"[2:]\"; // empty glyph cluster size\n// after\nglyphs.GlyphIndices = \"[2:1]\";","handlingStrategy":"validation","validationCode":"static bool ClusterPartsNonEmpty(string token) { int o = token.IndexOf('('), c = token.IndexOf(')'), col = token.IndexOf(':'); return col < 0 || (o >= 0 && c > col && col > o + 1 && col < c - 1); }\nif (!ClusterPartsNonEmpty(clusterToken)) throw new FormatException(\"Cluster must have non-empty parts around ':'\");","typeGuard":"static bool HasEmptyClusterSide(string token) { int col = token.IndexOf(':'); return col >= 0 && (col == 0 || col == token.Length - 1 || token[col-1] == '(' || token[col+1] == ')'); }","tryCatchPattern":"try { glyphs.GlyphIndices = value; }\ncatch (ArgumentException ex) { throw new FormatException($\"Invalid cluster separator in '{value}'\", ex); }","preventionTips":["Use 'n:1' explicitly when one side would be empty","Format cluster specs from a helper method instead of string concatenation","Add a regex check like '\\(\\d+:\\d+\\)' for cluster tokens"],"tags":["wpf","glyphs","parsing","xaml","argumentexception"],"backgroundTag":"invalid-argument-format","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}