dotnet/wpf · error · ArgumentOutOfRangeException

ArgumentOutOfRangeException(nameof(characterHit))

Error message

ArgumentOutOfRangeException(nameof(characterHit))

What it means

GetDistanceFromCaretCharacterHit throws ArgumentOutOfRangeException when the CharacterHit's FirstCharacterIndex is negative or greater than the GlyphRun's CodepointCount. Only character hits that fall inside the run's codepoint range are meaningful for caret distance measurement. The method checks this right after confirming the run is fully initialized.

Solutions

  1. Clamp or validate characterHit.FirstCharacterIndex to [0, glyphRun.CodepointCount] before calling.
  2. Ensure the CharacterHit originates from the same GlyphRun/text layout instance used for the distance query.
  3. Recompute character hits after any text content or layout change rather than reusing stale ones.

Example fix

// before
double d = run.GetDistanceFromCaretCharacterHit(hit);
// after
if (hit.FirstCharacterIndex < 0 || hit.FirstCharacterIndex > run.CodepointCount)
    hit = new CharacterHit(Math.Max(0, Math.Min(hit.FirstCharacterIndex, run.CodepointCount)));
double d = run.GetDistanceFromCaretCharacterHit(hit);
Defensive patterns

Strategy: validation

Validate before calling

bool inRange = characterHit.FirstCharacterIndex >= 0 && characterHit.FirstCharacterIndex <= glyphRun.CodepointCount;
if (!inRange) characterHit = new CharacterHit(Math.Clamp(characterHit.FirstCharacterIndex, 0, glyphRun.CodepointCount));

Type guard

bool IsValidHit(GlyphRun run, CharacterHit hit) => hit.FirstCharacterIndex >= 0 && hit.FirstCharacterIndex <= run.CodepointCount;

Try / catch

try { d = run.GetDistanceFromCaretCharacterHit(hit); }
catch (ArgumentOutOfRangeException) { d = 0; hit = new CharacterHit(0); }

Prevention

When it happens

Trigger: Calling glyphRun.GetDistanceFromCaretCharacterHit(new CharacterHit(-1, ...)) or with FirstCharacterIndex > glyphRun.CodepointCount. Typically a hit produced for a different GlyphRun or text source is passed to this run.

Common situations: Hit-testing code that maps a mouse position to a character hit on one run but measures distance on another; caching CharacterHit values across text layout rebuilds where CodepointCount changed; off-by-one arithmetic computing the hit index from character offsets.

Related errors


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

Appendix: source

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

        /// <summary>
        /// Given a character hit, computes the offset from the leading edge of the glyph run
        /// to the leading or trailing edge of a caret stop containing the character hit.
        /// If the glyph run is not hit testable, the distance of 0.0 is returned.
        /// </summary>
        /// <param name="characterHit">Character hit to compute the distance to.</param>
        /// <returns>The offset from the leading edge of the glyph run
        /// to the leading or trailing edge of a caret stop containing the character hit.</returns>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// The input character hit is outside of the range specified by the glyph run Unicode string.
        /// </exception>
        public double GetDistanceFromCaretCharacterHit(CharacterHit characterHit)
        {
            CheckInitialized(); // This can only be called on fully initialized GlyphRun

            IList<bool> caretStops = CaretStops != null && CaretStops.Count != 0 ? CaretStops : new DefaultCaretStopList(CodepointCount);
            if (characterHit.FirstCharacterIndex < 0 || characterHit.FirstCharacterIndex > CodepointCount)
                throw new ArgumentOutOfRangeException(nameof(characterHit));

            int caretStopIndex, codePointsUntilNextStop;
            FindNearestCaretStop(
                characterHit.FirstCharacterIndex,
                caretStops,
                out caretStopIndex,
                out codePointsUntilNextStop);

            // Not a hit testable glyph run.
            if (caretStopIndex == -1)
                return 0.0;

            // Trailing edge of a caret stop that doesn't have a corresponding valid next caret stop.
            if (codePointsUntilNextStop == -1 && characterHit.TrailingLength != 0)
            {
                return 0.0;
            }

View on GitHub (pinned to 81131a70a4)