dotnet/wpf · error · ArgumentException
SR.GlyphsUnicodeStringIsTooShort
Error message
SR.GlyphsUnicodeStringIsTooShort
What it means
Thrown by Glyphs.SetClusterMapEntry, the guarded writer for the clusterMap array built during Glyphs parsing. If the caller tries to write a cluster-map entry at an index at or beyond the array length, the UnicodeString is shorter than the glyph/cluster data implies. It is a validation guard meaning the Characters/UnicodeString supplied does not cover all parsed glyph indices.
Solutions
- Extend Glyphs.UnicodeString so it has at least as many characters as the cluster map requires.
- Reduce the number of glyph indices/clusters in GlyphIndices to match the UnicodeString length.
- Compute/check that parsedCharacterCount stays < UnicodeString.Length before writing cluster-map entries.
Example fix
// before glyphs.UnicodeString = "AB"; // 2 chars glyphs.GlyphIndices = ";(1:1);(2:1);(3:1)"; // needs >= 4 chars // after glyphs.UnicodeString = "ABCD"; glyphs.GlyphIndices = ";(1:1);(2:1);(3:1)";
Defensive patterns
Strategy: validation
Validate before calling
int impliedChars = CountClusterCharacters(glyphIndices); // sum characterClusterSize over cluster tokens
if (glyphs.UnicodeString == null || glyphs.UnicodeString.Length < impliedChars)
throw new InvalidOperationException("UnicodeString shorter than glyph cluster data"); Type guard
static bool UnicodeCoversClusters(string unicode, string indices) => unicode != null && unicode.Length >= indices.Split(';').Length; Try / catch
try { ApplyGlyphs(glyphs, indices, unicode); }
catch (ArgumentException ex) { RegenerateIndicesFromUnicode(glyphs); }
// recovery: rebuild GlyphIndices from the UnicodeString so lengths always agree Prevention
- Always generate GlyphIndices and UnicodeString together from one source of truth
- After editing UnicodeString, regenerate Indices
- Assert unicode.Length >= glyphEntryCount before assignment
When it happens
Trigger: Calling ParseGlyphsProperty (via Glyphs.GlyphIndices/UnicodeString assignment) where the number of characters implied by glyph clusters exceeds Glyphs.UnicodeString.Length — i.e. more cluster-map entries than characters.
Common situations: GlyphIndices and UnicodeString edited out of sync in XAML; adding a glyph cluster without adding corresponding characters to UnicodeString.
Related errors
- SR.GlyphsAdvanceWidthCannotBeNegative
- SR.GlyphsClusterMisplacedSeparator
- SR.GlyphsClusterNoMatchingBracket
- SR.GlyphsIndexRequiredIfNoUnicode
- SR.GlyphsIndexRequiredWithinCluster
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/1eaa0f52eef3c14b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/Glyphs.cs:466
return advance * EmMultiplier;
}
private ushort GetGlyphFromCharacter(GlyphTypeface glyphTypeface, char character)
{
ushort glyphIndex;
// TryGetValue will return zero glyph index for missing code points,
// which is the right thing to display per http://www.microsoft.com/typography/otspec/cmap.htm
glyphTypeface.CharacterToGlyphMap.TryGetValue(character, out glyphIndex);
return glyphIndex;
}
/// <summary>
/// Performs validation against cluster map size and throws a well defined exception.
/// </summary>
private static void SetClusterMapEntry(ushort[] clusterMap, int index, ushort value)
{
if (index < 0 || index >= clusterMap.Length)
throw new ArgumentException(SR.GlyphsUnicodeStringIsTooShort);
clusterMap[index] = value;
}
private class ParsedGlyphData
{
public ushort glyphIndex;
public double advanceWidth;
public double offsetX;
public double offsetY;
};
// -----------------------------------------------------------------------------
// Parses a semicolon-delimited list of glyph specifiers, each of which consists
// of up to 4 comma-delimited values:
// - glyph index (ushort)
// - glyph advance (double)
// - glyph offset X (double)
// - glyph offset Y (double)View on GitHub (pinned to 81131a70a4)