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

  1. 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.
  2. Defer document mutations until layout is not in progress (Dispatcher.BeginInvoke at background priority after the format pass).
  3. Re-create the FlowDocument content if the tree was deserialized or manipulated externally and pointers may be stale.
  4. 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

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


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)