dotnet/wpf · error · ArgumentException

SR.Format(SR.BadTextPositionOrder, "start", "end")

Error message

SR.Format(SR.BadTextPositionOrder, "start", "end")

What it means

The Span(TextPointer start, TextPointer end) constructor throws ArgumentException with SR.BadTextPositionOrder when start occurs after end in the text container (start.CompareTo(end) > 0). The constructor requires start to be at or before end, and both must already be in the same container (checked just before).

Solutions

  1. Normalize the two pointers with Min/Max before constructing: var s = start.CompareTo(end) <= 0 ? start : end; ...
  2. Order positions by document offset before calling the constructor.
  3. Guard with start.CompareTo(end) <= 0 and swap or report a clearer error beforehand.
  4. Catch ArgumentException and retry with swapped arguments.

Example fix

// before
var span = new Span(pointerA, pointerB);
// after
var (start, end) = pointerA.CompareTo(pointerB) <= 0 ? (pointerA, pointerB) : (pointerB, pointerA);
var span = new Span(start, end);
Defensive patterns

Strategy: validation

Validate before calling

if (start.CompareTo(end) > 0)
    (start, end) = (end, start); // normalize order before new Span(start, end)

Type guard

static (TextPointer, TextPointer) Ordered(TextPointer a, TextPointer b) =>
    a.CompareTo(b) <= 0 ? (a, b) : (b, a);

Try / catch

try { span = new Span(start, end); }
catch (ArgumentException ex) when (ex.Message.Contains("order")) { span = new Span(end, start); }

Prevention

When it happens

Trigger: new Span(start, end) where the caller passes the positions in reverse order relative to document flow - e.g. start from a selection end and end from the selection start.

Common situations: Using RichTextBox.Selection.Start/End inconsistently; building ranges from user selections where the anchor/focus order is not normalized; converting coordinates or offsets to pointers and getting them swapped.

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/f5e646342c3d717c. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/Span.cs:96

        /// </param>
        /// <param name="end">
        /// End position of the new Span.
        /// </param>
        /// <remarks>
        /// start and end must both be parented by the same Paragraph, otherwise
        /// the method will raise an ArgumentException.
        /// </remarks>
        public Span(TextPointer start, TextPointer end)
        {
            ArgumentNullException.ThrowIfNull(start);
            ArgumentNullException.ThrowIfNull(end);
            if (start.TextContainer != end.TextContainer)
            {
                throw new ArgumentException(SR.Format(SR.InDifferentTextContainers, "start", "end"));
            }
            if (start.CompareTo(end) > 0)
            {
                throw new ArgumentException(SR.Format(SR.BadTextPositionOrder, "start", "end"));
            }

            start.TextContainer.BeginChange();
            try
            {
                start = TextRangeEditTables.EnsureInsertionPosition(start);
                Invariant.Assert(start.Parent is Run);
                end = TextRangeEditTables.EnsureInsertionPosition(end);
                Invariant.Assert(end.Parent is Run);

                if (start.Paragraph != end.Paragraph)
                {
                    throw new ArgumentException(SR.Format(SR.InDifferentParagraphs, "start", "end"));
                }

                // If start or end positions have a Hyperlink ancestor, we cannot split them.
                Inline nonMergeableAncestor;
                if ((nonMergeableAncestor = start.GetNonMergeableInlineAncestor()) != null)

View on GitHub (pinned to 81131a70a4)