dotnet/wpf · error · ArgumentException
SR.MoreThanOneAttachedAnnotation
Error message
SR.MoreThanOneAttachedAnnotation
What it means
MarkedHighlightComponent.AddAttachedAnnotation throws ArgumentException(SR.MoreThanOneAttachedAnnotation) if the component already holds an attached annotation. Unlike HighlightComponent, a MarkedHighlightComponent (the visual markers for a highlight) represents exactly one attached annotation, so a second Add is a programming error.
Solutions
- Call RemoveAttachedAnnotation before adding a new annotation to the same component instance.
- Create a new MarkedHighlightComponent per attached annotation (this is what AnnotationService normally does).
- Check a public/internal IsAttached flag (or try to read the current annotation) before adding.
Example fix
// before
markedHighlight.AddAttachedAnnotation(newAttached);
// after
if (markedHighlight.AttachedAnnotation != null)
markedHighlight.RemoveAttachedAnnotation(markedHighlight.AttachedAnnotation);
markedHighlight.AddAttachedAnnotation(newAttached); Defensive patterns
Strategy: validation
Validate before calling
if (markedHighlight.AttachedAnnotation != null) markedHighlight.RemoveAttachedAnnotation(markedHighlight.AttachedAnnotation);
Type guard
static bool CanAcceptAnnotation(MarkedHighlightComponent c) => c.AttachedAnnotation == null;
Try / catch
try { component.AddAttachedAnnotation(a); } catch (ArgumentException) { component.RemoveAttachedAnnotation(component.AttachedAnnotation); component.AddAttachedAnnotation(a); } Prevention
- One MarkedHighlightComponent per attached annotation
- Do not re-enable AnnotationService without disabling first
- Fix custom locators that resolve multiple anchors to one component
When it happens
Trigger: Calling AddAttachedAnnotation twice on the same MarkedHighlightComponent instance without an intervening RemoveAttachedAnnotation; the AnnotationService routing two anchors to the same component.
Common situations: Duplicated anchors resolved by a custom LocatorPart to the same component; re-enabling a service without disabling first; loading overlapping annotations that resolve to one marker component.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.AnnotationIsNull
- SR.AnnotationServiceAlreadyExists
- SR.AnnotationServiceIsAlreadyEnabled
- SR.AnnotationServiceNotEnabled
- SR.Format(SR.ComponentAlreadyInPresentationContext…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/c05e1720cbd05ad6.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Annotations/Component/MarkedHighlightComponent.cs:203
//after the content reflow
if (_attachedAnnotation == null)
throw new InvalidOperationException(SR.InvalidAttachedAnnotation);
HighlightAnchor.GetDesiredTransform(transform);
return transform;
}
/// <summary>
/// Add an attached annotation to the component. The attached anchor will be used to add
/// a highlight to the appropriate TextContainer
/// </summary>
/// <param name="attachedAnnotation">The attached annotation to be added to the component</param>
public void AddAttachedAnnotation(IAttachedAnnotation attachedAnnotation)
{
if (_attachedAnnotation != null)
{
throw new ArgumentException(SR.MoreThanOneAttachedAnnotation);
}
//fire trace event
EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordAnnotation, EventTrace.Event.AddAttachedMHBegin);
//save the attached annotation
_attachedAnnotation = attachedAnnotation;
//create anchor markers
if ((attachedAnnotation.AttachmentLevel & AttachmentLevel.StartPortion) != 0)
_leftMarker = CreateMarker(GetMarkerGeometry());
if ((attachedAnnotation.AttachmentLevel & AttachmentLevel.EndPortion) != 0)
_rightMarker = CreateMarker(GetMarkerGeometry());
//create highlight, markers and register for TextSelection.Changed and other events
RegisterAnchor();
//fire trace eventView on GitHub (pinned to 81131a70a4)