dotnet/wpf · error · ArgumentException
SR.ClusterMapEntriesShouldNotDecrease
Error message
SR.ClusterMapEntriesShouldNotDecrease
What it means
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.
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
Example fix
// before
int[] clusterMap = { 2, 1, 0 };
// after
int[] clusterMap = { 0, 1, 2 }; // non-decreasing entries Defensive patterns
Strategy: validation
Validate before calling
if (clusterMap != null && clusterMap.Length > 0)
for (int i = 1; i < clusterMap.Length; i++)
if (clusterMap[i] < clusterMap[i-1]) throw new ArgumentException("clusterMap entries must not decrease"); Type guard
static bool IsValidClusterMap(int[] map, int glyphCount) =>
map == null || map.Length == 0 ||
(map[0] == 0 && map.All(v => v >= 0) && IsNonDecreasing(map) && map.All(v => v < glyphCount)); Try / catch
try { var run = new GlyphRun(...); }
catch (ArgumentException ex) when (ex.ParamName == "clusterMap") { /* rebuild map or log */ } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- SR.ClusterMapEntryShouldPointWithinGlyphIndices
- SR.ClusterMapFirstEntryMustBeZero
- SR.CollectionNumberOfElementsMustBeGreaterThanZero
- SR.Format(SR.CollectionNumberOfElementsMustBeLessOrEqualTo…
- SR.Format(SR.CollectionNumberOfElementsShouldBeEqualTo…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/5cb62baacf3e680f.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphRun.cs:384
// Perform some simple cluster map validation.
// First entry should be zero, the entries should be monotonic and shouldn't point outside of the glyph indices range.
if (clusterMap[0] == 0)
{
int glyphCount = GlyphCount;
int mapCount = clusterMap.Count;
ushort previous = clusterMap[0];
for (int i = 1; i < mapCount; ++i)
{
ushort current = clusterMap[i];
if ((current >= previous) && (current < glyphCount))
{
previous = current;
}
else
{
if (clusterMap[i] < clusterMap[i - 1])
throw new ArgumentException(SR.ClusterMapEntriesShouldNotDecrease, nameof(clusterMap));
if (clusterMap[i] >= GlyphCount)
throw new ArgumentException(SR.ClusterMapEntryShouldPointWithinGlyphIndices, nameof(clusterMap));
}
}
}
else
{
throw new ArgumentException(SR.ClusterMapFirstEntryMustBeZero, nameof(clusterMap));
}
}
else
{
throw new ArgumentException(SR.Format(SR.CollectionNumberOfElementsShouldBeEqualTo, characters.Count), nameof(clusterMap));
}
}
else
{View on GitHub (pinned to 81131a70a4)