{"record":{"id":"5cb62baacf3e680f","repo":"dotnet/wpf","slug":"sr-clustermapentriesshouldnotdecrease","errorCode":null,"errorMessage":"SR.ClusterMapEntriesShouldNotDecrease","messagePattern":"SR\\.ClusterMapEntriesShouldNotDecrease","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphRun.cs","lineNumber":384,"sourceCode":"                            // Perform some simple cluster map validation.\n                            // First entry should be zero, the entries should be monotonic and shouldn't point outside of the glyph indices range.\n                            if (clusterMap[0] == 0)\n                            {\n                                int glyphCount = GlyphCount;\n                                int mapCount = clusterMap.Count;\n                                ushort previous = clusterMap[0];\n\n                                for (int i = 1; i < mapCount; ++i)\n                                {\n                                    ushort current = clusterMap[i];\n                                    if ((current >= previous) && (current < glyphCount))\n                                    {\n                                        previous = current;\n                                    }\n                                    else\n                                    {\n                                        if (clusterMap[i] < clusterMap[i - 1])\n                                            throw new ArgumentException(SR.ClusterMapEntriesShouldNotDecrease, nameof(clusterMap));\n\n                                        if (clusterMap[i] >= GlyphCount)\n                                            throw new ArgumentException(SR.ClusterMapEntryShouldPointWithinGlyphIndices, nameof(clusterMap));\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                throw new ArgumentException(SR.ClusterMapFirstEntryMustBeZero, nameof(clusterMap));\n                            }\n                        }\n                        else\n                        {\n                            throw new ArgumentException(SR.Format(SR.CollectionNumberOfElementsShouldBeEqualTo, characters.Count), nameof(clusterMap));\n                        }\n                    }\n                    else\n                    {","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphRun.cs#L366-L402","documentation":"GlyphRun.Initialize validates that the clusterMap (when non-null and non-empty) is monotonically non-decreasing: each entry must be >= the previous entry. A decreasing entry means the mapping from characters to glyph indices is inconsistent, so the library refuses to construct the GlyphRun. It throws ArgumentException naming the clusterMap parameter.","triggerScenarios":"Calling the GlyphRun constructor, GlyphRun.TryCreate, or EndInit (ISupportInitialize) with a non-null clusterMap array where some clusterMap[i] < clusterMap[i-1], e.g. building the map manually or reordering entries without resorting.","commonSituations":"Hand-rolling cluster maps when converting shaped text to GlyphRun; copying subset of clusters from another run but slicing the map at wrong offsets; mixing cluster maps from different shaping engines.","solutions":["Sort/normalize the cluster map so entries are non-decreasing before constructing the GlyphRun","Regenerate the clusterMap with a proper text shaper (e.g. GlyphTypeface/TextFormatter output) instead of hand-building it","Ensure slices of clusterMap and characters/glyphIndices come from the same source run"],"exampleFix":"// before\nint[] clusterMap = { 2, 1, 0 };\n// after\nint[] clusterMap = { 0, 1, 2 }; // non-decreasing entries","handlingStrategy":"validation","validationCode":"if (clusterMap != null && clusterMap.Length > 0)\n    for (int i = 1; i < clusterMap.Length; i++)\n        if (clusterMap[i] < clusterMap[i-1]) throw new ArgumentException(\"clusterMap entries must not decrease\");","typeGuard":"static bool IsValidClusterMap(int[] map, int glyphCount) =>\n    map == null || map.Length == 0 ||\n    (map[0] == 0 && map.All(v => v >= 0) && IsNonDecreasing(map) && map.All(v => v < glyphCount));","tryCatchPattern":"try { var run = new GlyphRun(...); }\ncatch (ArgumentException ex) when (ex.ParamName == \"clusterMap\") { /* rebuild map or log */ }","preventionTips":["Never hand-edit cluster maps; derive them from shaper output","Validate non-decreasing order before constructing the run","Keep clusterMap and glyphIndices slices from the same source"],"tags":["wpf","glyphrun","argument-validation"],"backgroundTag":"invalid-argument-value","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"}