dotnet/wpf · error · ArgumentException

SR.ClusterMapFirstEntryMustBeZero

Error message

SR.ClusterMapFirstEntryMustBeZero

What it means

When a clusterMap is supplied to GlyphRun.Initialize, its first entry must be 0, indicating the first character maps to the first glyph. Any other first value leaves leading characters unmapped, so the run is rejected with ArgumentException on the clusterMap parameter.

Solutions

  1. Ensure clusterMap[0] == 0 (rebase entries by subtracting the original start offset)
  2. Regenerate the map for the exact character/glyph range of this run
  3. Skip passing clusterMap (pass null) if cluster information is not needed

Example fix

// before (sub-run of map {0,0,2,3} starting at index 2)
int[] clusterMap = { 2, 3 };
// after
int[] clusterMap = { 0, 1 }; // rebased to start at 0
Defensive patterns

Strategy: validation

Validate before calling

if (clusterMap != null && clusterMap.Length > 0 && clusterMap[0] != 0)
    clusterMap = RebaseToZero(clusterMap);

Type guard

static bool FirstEntryIsZero(int[] map) => map == null || map.Length == 0 || map[0] == 0;

Try / catch

try { var run = new GlyphRun(...); }
catch (ArgumentException ex) when (ex.ParamName == "clusterMap") { /* rebase offsets */ }

Prevention

When it happens

Trigger: Calling the GlyphRun constructor, TryCreate, or EndInit with a clusterMap whose element 0 is non-zero, e.g. slicing a map from a larger run starting mid-cluster.

Common situations: Extracting a sub-run from shaped text and reusing the tail of the original clusterMap; off-by-one indexing when the shaper emits 1-based-looking values.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/7d4245f832936c5c. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/GlyphRun.cs:393

                                {
                                    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
                    {
                        if (GlyphCount != characters.Count)
                            throw new ArgumentException(SR.Format(SR.CollectionNumberOfElementsShouldBeEqualTo, GlyphCount), nameof(clusterMap));
                    }
                }

                if (caretStops != null && caretStops.Count != 0)
                {
                    if (caretStops.Count != CodepointCount + 1)
                        throw new ArgumentException(SR.Format(SR.CollectionNumberOfElementsShouldBeEqualTo, CodepointCount + 1), nameof(caretStops));

View on GitHub (pinned to 81131a70a4)