dotnet/wpf · error · InvalidOperationException
SR.OnlyFlowFixedSupported
Error message
SR.OnlyFlowFixedSupported
What it means
AnnotationHelper.CheckInputs throws InvalidOperationException when the enabled AnnotationService's Root viewer has a null Document. Annotation helpers only work against flow or fixed documents hosted in DocumentViewerBase, FlowDocumentReader, or FlowDocumentScrollViewer; if the viewer currently hosts no document there is nothing to annotate. The Invariant.Assert above guarantees the root is a supported viewer type, so a null Document is reported via this dedicated exception.
Solutions
- Ensure the viewer's Document property is set (and non-null) before calling AnnotationHelper methods.
- Delay annotation commands until document load completes (e.g. handle Loaded event of the viewer).
- Guard helper calls with a null check on the viewer's Document.
- Verify the annotation service is attached to the viewer that actually hosts the document, not a different instance.
Example fix
// before
AnnotationHelper.CreateTextStickyNoteForSelection(service, author, anchorRes, rects);
// after
if (fdvViewer.Document != null)
AnnotationHelper.CreateTextStickyNoteForSelection(service, author, anchorRes, rects); Defensive patterns
Strategy: validation
Validate before calling
var viewer = service.Root as DocumentViewerBase ?? (DependencyObject)service.Root as FlowDocumentScrollViewer;
bool documentLoaded = viewer != null &&
(viewer is DocumentViewerBase dv ? dv.Document != null : ((FlowDocumentScrollViewer)viewer).Document != null);
if (!documentLoaded) return; // wait for document load Type guard
bool HasDocument(AnnotationService s) =>
(s.Root as DocumentViewerBase)?.Document != null ||
(s.Root as FlowDocumentScrollViewer)?.Document != null; Try / catch
try { AnnotationHelper.CreateTextStickyNoteForSelection(service, ...); }
catch (InvalidOperationException) { /* defer until document is loaded */ } Prevention
- Hook annotation commands to fire only after the viewer's Document is assigned.
- Set the Document before enabling the annotation service.
- Re-check Document after async navigation or load operations.
When it happens
Trigger: Calling an AnnotationHelper method while the service is enabled but its Root viewer (e.g. DocumentViewerBase.Document or FlowDocumentScrollViewer.Document) is null — the viewer has no document loaded.
Common situations: Invoking annotation commands from UI wiring before the document is set on the viewer; document unloaded asynchronously while a helper is invoked; binding or navigation that clears Document during startup.
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
- SR.AnnotationServiceAlreadyExists
- SR.AnnotationServiceIsAlreadyEnabled
- SR.AnnotationServiceNotEnabled
- SR.Format(SR.ComponentAlreadyInPresentationContext…
- SR.Format(SR.ComponentNotInPresentationContext, component)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/64c9b51d8885422b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Annotations/AnnotationHelper.cs:1098
ArgumentNullException.ThrowIfNull(service);
if (!service.IsEnabled)
{
throw new ArgumentException(SR.AnnotationServiceNotEnabled, nameof(service));
}
DocumentViewerBase viewer = service.Root as DocumentViewerBase;
if (viewer == null)
{
FlowDocumentScrollViewer scrollViewer = service.Root as FlowDocumentScrollViewer;
FlowDocumentReader reader = service.Root as FlowDocumentReader;
Invariant.Assert((scrollViewer != null) || (reader != null), "Service's Root must be either a FlowDocumentReader, DocumentViewerBase or a FlowDocumentScrollViewer.");
}
else
{
if (viewer.Document == null)
{
throw new InvalidOperationException(SR.OnlyFlowFixedSupported);
}
}
}
/// <summary>
/// Determines if a command should be enabled based on four things:
/// 1. Existing of a service
/// 2. Service is enabled
/// 3. Selection available
/// 4. Selection is not empty (optional)
/// </summary>
/// <param name="sender">DocumentViewerBase the command will operate on</param>
/// <param name="checkForEmpty">whether to check for empty selection or not</param>
/// <returns>true if the command should be enabled; false otherwise</returns>
private static bool IsCommandEnabled(object sender, bool checkForEmpty)
{
Invariant.Assert(sender != null, "Parameter 'sender' is null.");
View on GitHub (pinned to 81131a70a4)