AvaloniaUI/Avalonia · error · ArgumentOutOfRangeException

{nameof(textLength)} ('0') must be a non-zero value.

Error message

{nameof(textLength)} ('0') must be a non-zero value. 

What it means

Thrown by TextLineImpl.GetTextBounds when textLength is exactly zero. GetTextBounds computes the bounding rectangles for a range of characters within a formatted text line; a zero-length range has no meaningful bounds, so Avalonia rejects it outright. The caller must request a non-zero character span.

Source

Thrown at src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs:677

                    break;
                }

                if (nextRun is DrawableTextRun nextDrawable)
                {
                    directionalWidth += nextDrawable.Size.Width;
                }

                lastRunIndex = nextIndexedRun.RunIndex;
            }

            return lastRunIndex;
        }

        public override IReadOnlyList<TextBounds> GetTextBounds(int firstTextSourceIndex, int textLength)
        {
            if (textLength == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(textLength), textLength, $"{nameof(textLength)} ('0') must be a non-zero value. ");
            }

            if (_indexedTextRuns is null || _indexedTextRuns.Count == 0)
            {
                return [];
            }

            var currentPosition = FirstTextSourceIndex;
            var remainingLength = textLength;

            //We can return early if the requested text range is before the line's text range.
            if (firstTextSourceIndex + textLength < FirstTextSourceIndex)
            {
                var indexedTextRun = _indexedTextRuns[0];
                var currentDirection = GetRunDirection(indexedTextRun.TextRun, _resolvedFlowDirection);

                return [new TextBounds(new Rect(0, 0, 0, Height), currentDirection, [])];
            }

View on GitHub (pinned to 11c5427268)

Solutions

  1. Guard the call site: if (textLength == 0) return an empty bounds list instead of calling GetTextBounds.
  2. Ensure the computed textLength is always at least 1 when a real range is intended.
  3. If performing caret hit-testing with a degenerate (empty) selection, skip the GetTextBounds call entirely.

Example fix

// before
var bounds = line.GetTextBounds(startIndex, endIndex - startIndex); // throws when equal

// after
var length = endIndex - startIndex;
var bounds = length > 0
    ? line.GetTextBounds(startIndex, length)
    : Array.Empty<TextBounds>();
Defensive patterns

Strategy: validation

Validate before calling

static IReadOnlyList<TextBounds> SafeGetBounds(TextLine line, int first, int len)
{
    if (len <= 0) return Array.Empty<TextBounds>();
    return line.GetTextBounds(first, len);
}

Prevention

When it happens

Trigger: Calling textLine.GetTextBounds(firstTextSourceIndex, 0) — i.e. passing a textLength of zero to an already-formatted TextLine instance. Common when the length is computed from a subtraction that yields zero, or when a measurement routine is called with an empty selection range.

Common situations: Text selection/caret-hit-testing code that computes length as (end - start) and passes it through without clamping; caret positioned at start==end producing a zero-length bounds request; automated layout passes that probe with zero-length ranges.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/fea124e752207bb8. Report an issue: GitHub.