dotnet/wpf · error · ArgumentException

SR.TextRangeProvider_WrongTextRange

Error message

SR.TextRangeProvider_WrongTextRange

What it means

TextRangeAdaptor.ValidateAndThrow throws ArgumentException when the supplied ITextRangeProvider is either not a TextRangeAdaptor instance or belongs to a different TextContainer than this adaptor. UI Automation range APIs require ranges that live in the same text container they operate on.

Solutions

  1. Verify the range was obtained from the same control's TextPattern/TextRangeProvider as the one the method is invoked on; re-acquire it via pattern.DocumentRange or the correct provider if not.
  2. Before use, cast to TextRangeAdaptor and compare the underlying TextContainer, mirroring the guard in ValidateAndThrow.
  3. Stop caching TextRangeProviders across control instances; fetch ranges per-target control at call time.
  4. If interoperating with non-WPF providers, translate the range into the target container rather than passing it directly.

Example fix

// before: applying a cached range from another control
var range = otherTextPattern.DocumentRange;
targetAdaptor.FindText("query", /* searchBackward */ false, /* ignoreCase */ true, ref range); // throws

// after: use a range that belongs to the same container
var ownPattern = (TextPattern)targetElement.GetCurrentValue(TextPattern.Pattern);
var range = ownPattern.DocumentRange;
targetAdaptor.FindText("query", false, true, ref range); // same container: OK
Defensive patterns

Strategy: type-guard

Validate before calling

// before invoking a TextRangeAdaptor API with a foreign range:
bool containerMatches = range is TextRangeAdaptor adapt && adapt != null;
// full guard requires comparing containers as the library does:
// adaptor._start.TextContainer == targetAdaptor._start.TextContainer

Type guard

static bool IsValidForTarget(ITextRangeProvider range, TextRangeAdaptor target)
    => range is TextRangeAdaptor adaptor && adaptor._start?.TextContainer == target._start.TextContainer;

Try / catch

try
{
    targetAdaptor.FindText("query", false, true, ref range);
}
catch (ArgumentException ex) when (ex.Message.Contains("range"))
{
    range = ownPattern.DocumentRange; // re-acquire a range from the same container and retry
    targetAdaptor.FindText("query", false, true, ref range);
}

Prevention

When it happens

Trigger: Calling a TextRangeAdaptor method (e.g. FindText, Select, CompareTo, Clone-and-modify patterns) passing an ITextRangeProvider that came from a different control's TextPattern or from a non-WPF provider (null after the 'as' cast), so rangeAdaptor is null or its _start.TextContainer differs from the current _start.TextContainer.

Common situations: Mixing ranges across two TextBox/TextBlock/RichTextBox instances in UIA automation code; caching a TextRangeProvider from one control and applying it to another after the visual tree changed; passing a foreign/provider range (e.g. from a mock or another framework) into a WPF TextPattern operation.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextRangeAdaptor.cs:510

        //-------------------------------------------------------------------
        //
        //  Private Methods
        //
        //-------------------------------------------------------------------

        #region Private Methods

        /// <summary>
        /// Verifies that the given range points to the same text container as this one.
        /// </summary>
        /// <returns>The validated range casted to TextRangeAdaptor</returns>
        private TextRangeAdaptor ValidateAndThrow(ITextRangeProvider range)
        {
            TextRangeAdaptor rangeAdaptor = range as TextRangeAdaptor;
            if (rangeAdaptor == null || rangeAdaptor._start.TextContainer != _start.TextContainer)
            {
                throw new ArgumentException(SR.TextRangeProvider_WrongTextRange);
            }
            return rangeAdaptor;
        }

        /// <summary>
        /// Expands the range to an integral number of enclosing units.  If the range is already an
        /// integral number of the specified units then it remains unchanged.
        /// </summary>
        private void ExpandToEnclosingUnit(TextUnit unit, bool expandStart, bool expandEnd)
        {
            ITextView textView;
            switch (unit)
            {
                case TextUnit.Character:
                    if (expandStart && !TextPointerBase.IsAtInsertionPosition(_start))
                    {
                        TextPointerBase.MoveToNextInsertionPosition(_start, LogicalDirection.Backward);
                    }

View on GitHub (pinned to 81131a70a4)