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
- Normalize the two pointers with Min/Max before constructing: var s = start.CompareTo(end) <= 0 ? start : end; ...
- Order positions by document offset before calling the constructor.
- Guard with start.CompareTo(end) <= 0 and swap or report a clearer error beforehand.
- 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
- Always normalize selection anchor/focus into start/end order
- Use selection.Start/End (already ordered) instead of raw pointers
- Write a small Ordered() helper and use it everywhere ranges are built
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
- SR.Format(SR.InDifferentTextContainers, "start", "end")
- args
- ArgumentNullException(paramName)
- Invalid priority range order.
- Not implemented.
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)