dotnet/wpf · error · InvalidOperationException
SR.Format(SR.TextSchema_TextIsNotAllowedInThisContext…
Error message
SR.Format(SR.TextSchema_TextIsNotAllowedInThisContext, Element.GetType().Name)
What it means
During PTS layout, ContainerParagraph.GetParagraph builds a TextParagraph from an element's TextPointer. If the pointer falls before the start of the text container, the workaround check tolerates it only when the element is a TextElement and the pointer is exactly its ContentStart; otherwise the document tree is in a state where a text run exists in an illegal position, and an InvalidOperationException (TextSchema_TextIsNotAllowedInThisContext) is thrown naming the offending element type.
Solutions
- Audit recent programmatic edits to the document for content placed outside valid TextElement boundaries; rebuild the offending element or insert text via TextPointer.InsertTextInRun on positions inside the container.
- Defer document mutations until layout is not in progress (Dispatcher.BeginInvoke at background priority after the format pass).
- Re-create the FlowDocument content if the tree was deserialized or manipulated externally and pointers may be stale.
- If reproducible, capture the element type named in the message and inspect its ContentStart/TextContainer position to find the invalid insert.
Example fix
// before (mutating during layout) doc.Blocks.Add(paragraph); // inside LayoutUpdated handler -> layout walks invalid position // after Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => doc.Blocks.Add(paragraph)));
Defensive patterns
Strategy: try-catch
Validate before calling
bool pointerIsValid = !(textPointer.TextContainer.Start.CompareTo(textPointer) > 0) || (element is TextElement te && te.ContentStart == textPointer);
Type guard
static bool IsTextElementWithValidStart(object e, TextPointer p) => e is TextElement te && te.ContentStart == p;
Try / catch
try { formatter.Format(documentPage); }
catch (InvalidOperationException ex) when (ex.Message.Contains("not allowed in this context")) { RebuildDocumentTree(doc); } Prevention
- Do not mutate FlowDocument content while a layout/format pass is in progress
- Route all edits through TextPointer/TextRange APIs that respect element boundaries
- Defer batched document edits to background Dispatcher priority
- Keep TextPointer usage on the thread that owns the text container
When it happens
Trigger: Performing a full-layout pass (formatter.Validate / CreateAndFormatLine drives GetFirstPara/GetNextPara) over a FlowDocument/TextBlock whose content tree violates the text schema — e.g. a TextPointer positioned before ContentStart of a non-TextElement, or corrupted/incoherent element boundaries after programmatic edits.
Common situations: Heavy programmatic manipulation of FlowDocument content (inserting runs/inline collections while a previous layout is still pending), sharing a TextPointer across threads, or editing document content during the LayoutUpdated/paging pass.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- SR.FlowDocumentFormattingReentrancy
- SR.FlowDocumentFormattingReentrancy
- SR.FlowDocumentInvalidContnetChange
- SR.FlowDocumentInvalidContnetChange
- SR.Format(SR.PTSError, fserr)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/ad54899e060a7b2c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/PtsHost/ContainerParagraph.cs:1001
// * if block, UIElementParagraph
// * if inline, TextParagraph
// (5) if textPointer points to TextContainer.End, NULL
// ------------------------------------------------------------------
protected virtual BaseParagraph GetParagraph(ITextPointer textPointer, bool fEmptyOk)
{
BaseParagraph paragraph = null;
switch (textPointer.GetPointerContext(LogicalDirection.Forward))
{
case TextPointerContext.Text:
// Text paragraph
// WORKAROUND FOR SCHEMA VALIDATION
if(textPointer.TextContainer.Start.CompareTo(textPointer) > 0)
{
if(!(Element is TextElement) || ((TextElement)Element).ContentStart != textPointer)
{
throw new InvalidOperationException(SR.Format(SR.TextSchema_TextIsNotAllowedInThisContext, Element.GetType().Name));
}
}
paragraph = new TextParagraph(Element, StructuralCache);
break;
case TextPointerContext.ElementEnd:
// The end of TextElement
Invariant.Assert(textPointer is TextPointer);
Invariant.Assert(Element == ((TextPointer)textPointer).Parent);
if(!fEmptyOk)
{
paragraph = new TextParagraph(Element, StructuralCache);
}
break;
case TextPointerContext.ElementStart:View on GitHub (pinned to 81131a70a4)