dotnet/wpf · error · InvalidOperationException

SR.Format(SR.TextSchema_ChildTypeIsInvalid…

Error message

SR.Format(SR.TextSchema_ChildTypeIsInvalid, this.Parent.GetType().Name, child.GetType().Name)

What it means

Thrown by InlineCollection.ValidateChild when adding a child that is not a valid content child of its parent text container (e.g. adding a Run to a Hyperlink's collection in a position where the schema disallows it, or a Paragraph into a Span-like container that forbids it). When the parent is not a TextElement the fallback schema check IsValidChildOfContainer runs and throws InvalidOperationException naming both types.

Solutions

  1. Use the correct collection: add Inline-derived elements (Run, Span, Hyperlink) to InlineCollection; add Block-derived elements (Paragraph, Table) to BlockCollection.
  2. Wrap text-level content in an inline container: replace Paragraph with Run or Span when inserting into an InlineCollection.
  3. Check TextSchema.IsValidChildOfContainer(parentType, childType) before Add to fail fast with a clearer message.

Example fix

// before
paragraph.Inlines.Add(new Paragraph(new Run("text"))); // Block into Inlines
// after
paragraph.Inlines.Add(new Run("text"));
Defensive patterns

Strategy: type-guard

Validate before calling

static bool CanAdd(TextElementCollection<TextElement> c, object child) => c.Parent == null || TextSchema.IsValidChildOfContainer(c.Parent.GetType(), child.GetType());
if (!CanAdd(inlines, child)) throw new InvalidOperationException($"{child.GetType().Name} not allowed in {inlines.Parent?.GetType().Name}");

Type guard

static bool IsInline(object o) => o is Inline; // use before adding: if (IsInline(child) && parent is TextElement) inlines.Add((Inline)child);

Try / catch

try { inlines.Add(child); }
catch (InvalidOperationException ex) { logger.Warn(ex, "Rejected child {Child} for {Parent}", child.GetType().Name, inlines.Parent?.GetType().Name); }

Prevention

When it happens

Trigger: Calling inlineCollection.Add(child) (or AddRange/insert via XAML) where child.GetType() is not permitted inside Parent's type per TextSchema — e.g. adding a Block-derived element (Paragraph) into an InlineCollection owned by a Span/Paragraph/Hyperlink, or adding non-TextElement objects.

Common situations: Building FlowDocument content in code and mixing Block (Paragraph) with Inline (Run/Span) levels; XAML that nests a Paragraph inside a Bold/Italic/Hyperlink; data-bound collections inserting UIElement or arbitrary objects into text content.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/0cdeca35137b71d4. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/InlineCollection.cs:167

        /// <summary>
        /// This method performs schema validation for inline collections. 
        /// (1) We want to disallow nested Hyperlink elements. 
        /// (2) Also, a Hyperlink element allows only these child types: Run, InlineUIContainer and Span elements other than Hyperlink.
        /// </summary>
        internal override void ValidateChild(Inline child)
        {
            base.ValidateChild(child);

            if (this.Parent is TextElement)
            {
                TextSchema.ValidateChild((TextElement)this.Parent, child, true /* throwIfIllegalChild */, true /* throwIfIllegalHyperlinkDescendent */);
            }
            else
            {
                if (!TextSchema.IsValidChildOfContainer(this.Parent.GetType(), child.GetType()))
                {
                    throw new InvalidOperationException(SR.Format(SR.TextSchema_ChildTypeIsInvalid, this.Parent.GetType().Name, child.GetType().Name));
                }
            }
        }

        #endregion Internal Methods

        //-------------------------------------------------------------------
        //
        //  Private Methods
        //
        //-------------------------------------------------------------------

        #region Private Methods

        // Worker for OnAdd and Add(string).
        // If returnIndex == true, uses the more costly IList.Add
        // to calculate and return the index of the newly inserted
        // Run, otherwise returns -1.

View on GitHub (pinned to 81131a70a4)