dotnet/wpf · error · ArgumentException

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

Error message

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

What it means

The Span(TextPointer start, TextPointer end) constructor throws ArgumentException with SR.InDifferentParagraphs when, after normalizing both positions to insertion positions inside Runs, the positions resolve to different Paragraph elements. A Paragraph-range Span (used for Paragraph construction/scoping) must lie entirely within one paragraph.

Solutions

  1. Only construct this Span when both positions are inside the same Paragraph (compare start.Paragraph and end.Paragraph).
  2. Split multi-paragraph ranges into one Span per paragraph and process each separately.
  3. Use TextRange (which supports cross-paragraph ranges) instead of Span when the range legitimately spans paragraphs.
  4. Catch ArgumentException and fall back to a TextRange-based implementation.

Example fix

// before
var span = new Span(selection.Start, selection.End); // may cross paragraphs
// after
if (selection.Start.Paragraph != selection.End.Paragraph)
    return null; // or handle per paragraph
var span = new Span(selection.Start, selection.End);
Defensive patterns

Strategy: validation

Validate before calling

if (start.Paragraph != end.Paragraph)
    throw new ArgumentException("Span range must lie within a single paragraph.");

Type guard

static bool WithinOneParagraph(TextPointer a, TextPointer b) => a.Paragraph != null && a.Paragraph == b.Paragraph;

Try / catch

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

Prevention

When it happens

Trigger: new Span(start, end) where start and end are in the same document but in different Paragraph (or paragraph-like block) elements - e.g. start in paragraph 1 and end in paragraph 2 of a FlowDocument.

Common situations: Selecting across multiple paragraphs and passing the selection endpoints to create a paragraph-scoped Span; using document-wide Start/End pointers; processing a document line-by-line but pairing pointers from adjacent paragraphs.

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

Appendix: source

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

            {
                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)
                {
                    throw new InvalidOperationException(SR.Format(SR.TextSchema_CannotSplitElement, nonMergeableAncestor.GetType().Name));
                }
                if ((nonMergeableAncestor = end.GetNonMergeableInlineAncestor()) != null)
                {
                    throw new InvalidOperationException(SR.Format(SR.TextSchema_CannotSplitElement, nonMergeableAncestor.GetType().Name));
                }

                TextElement commonAncestor = TextElement.GetCommonAncestor((TextElement)start.Parent, (TextElement)end.Parent);

                while (start.Parent != commonAncestor)
                {
                    start = SplitElement(start);

View on GitHub (pinned to 81131a70a4)