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
- Build the locator part via TextSelectionProcessor.GenerateLocatorParts so both Start and Count attributes are populated.
- Validate locatorPart.NameValuePairs contains CountAttribute before calling ResolveLocatorPart.
- Recreate the locator from the original selection if the stored part is malformed.
- 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
- Always build CharacterRange locator parts via GenerateLocatorParts (never by hand).
- Validate Start and Count attributes exist on stored locator parts before resolving.
- Sanity-check annotation stores after schema/version upgrades.
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
- SR.AnnotationServiceNotEnabled
- SR.Format(SR.IncorrectLocatorPartType, " : ")
- SR.Format(SR.RequiredAttributeMissing…
- SR.Format(SR.RequiredAttributeMissing…
- SR.Format(SR.RequiredAttributeMissing…
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)