dotnet/wpf · error · ArgumentException

SR.Format(SR.InvalidLocatorPart…

Error message

SR.Format(SR.InvalidLocatorPart, TextSelectionProcessor.CountAttribute)

What it means

ResolveLocatorPart reads the 'Count' attribute from the locator part's name/value pairs to determine the character-range length. If the attribute is missing the locator part is malformed and cannot be resolved, so this ArgumentException is thrown naming the missing attribute.

Solutions

  1. Build the locator part via TextSelectionProcessor.GenerateLocatorParts so both Start and Count attributes are populated.
  2. Validate locatorPart.NameValuePairs contains CountAttribute before calling ResolveLocatorPart.
  3. Recreate the locator from the original selection if the stored part is malformed.
  4. Catch ArgumentException and treat the locator as unresolvable (AttachmentLevel.Unresolved).

Example fix

// before
var part = new ContentLocatorPart(TextSelectionProcessor.CharacterRangeElementName);
part.NameValuePairs[TextSelectionProcessor.SegmentAttribute] = "10";
var anchor = processor.ResolveLocatorPart(part, startNode, out level);
// after
var part = new ContentLocatorPart(TextSelectionProcessor.CharacterRangeElementName);
part.NameValuePairs[TextSelectionProcessor.SegmentAttribute] = "10";
part.NameValuePairs[TextSelectionProcessor.CountAttribute] = "25";
var anchor = processor.ResolveLocatorPart(part, startNode, out level);
Defensive patterns

Strategy: validation

Validate before calling

if (locatorPart.NameValuePairs[TextSelectionProcessor.CountAttribute] == null)
    throw new InvalidOperationException("LocatorPart missing Count attribute");

Type guard

static bool HasCountAttribute(ContentLocatorPart p) => p.NameValuePairs[TextSelectionProcessor.CountAttribute] != null;

Try / catch

try { result = processor.ResolveLocatorPart(locatorPart, startNode, out level); }
catch (ArgumentException ex) when (ex.Message.Contains(TextSelectionProcessor.CountAttribute)) { level = AttachmentLevel.Unresolved; result = null; }

Prevention

When it happens

Trigger: Passing a CharacterRange-typed ContentLocatorPart that lacks the CountAttribute ('Count') name/value pair — e.g. constructed by hand with only Start set, deserialized with missing attributes, or corrupted/partial annotation data.

Common situations: Hand-rolling ContentLocatorPart entries instead of using GenerateLocatorParts; annotation streams from older/other versions with a different schema; manual XML editing of annotation stores.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Anchoring/TextSelectionProcessor.cs:201

        /// <exception cref="ArgumentNullException">locatorPart or startNode are
        /// null</exception>
        /// <exception cref="ArgumentException">locatorPart is of the incorrect type</exception>
        public override Object ResolveLocatorPart(ContentLocatorPart locatorPart, DependencyObject startNode, out AttachmentLevel attachmentLevel)
        {
            ArgumentNullException.ThrowIfNull(startNode);
            ArgumentNullException.ThrowIfNull(locatorPart);

            if (CharacterRangeElementName != locatorPart.PartType)
                throw new ArgumentException(SR.Format(SR.IncorrectLocatorPartType, $"{locatorPart.PartType.Namespace}:{locatorPart.PartType.Name}"), nameof(locatorPart));

            // First we extract the offset and length of the
            // text range from the locator part.
            int startOffset = 0;
            int endOffset = 0;

            string stringCount = locatorPart.NameValuePairs[CountAttribute];
            if (stringCount == null)
                throw new ArgumentException(SR.Format(SR.InvalidLocatorPart, TextSelectionProcessor.CountAttribute));
            int count = Int32.Parse(stringCount, NumberFormatInfo.InvariantInfo);

            TextAnchor anchor = new TextAnchor();

            attachmentLevel = AttachmentLevel.Unresolved;

            for (int i = 0; i < count; i++)
            {
                GetLocatorPartSegmentValues(locatorPart, i, out startOffset, out endOffset);

                // Now we grab the TextRange so we can create a selection.
                // TextBox doesn't expose its internal TextRange so we use
                // its API for creating and getting the selection.
                ITextPointer elementStart;
                ITextPointer elementEnd;
                // If we can't get the start/end of the node then we can't resolve the locator part
                if (!GetNodesStartAndEnd(startNode, out elementStart, out elementEnd))
                    return null;

View on GitHub (pinned to 81131a70a4)