dotnet/wpf · error · InvalidOperationException

SR.Format(SR.TableInvalidParentNodeType…

Error message

SR.Format(SR.TableInvalidParentNodeType, newParent.GetType().ToString())

What it means

TableRowGroup.OnNewParent validates that a row group's new parent is a Table (or null). Reparenting a TableRowGroup to any other DependencyObject throws InvalidOperationException naming the actual type, because TableRowGroup may only be a direct child of a Table's RowGroups collection.

Solutions

  1. Add the TableRowGroup to a Table's RowGroups collection
  2. Fix XAML so TableRowGroup is a direct child of Table
  3. Check 'newParent is Table' before reparenting

Example fix

// before
stackPanel.Children.Add(rowGroup); // invalid parent
// after
var table = new Table();
table.RowGroups.Add(rowGroup);
Defensive patterns

Strategy: validation

Validate before calling

bool ok = newParent == null || newParent is Table;

Type guard

static bool CanParentRowGroup(DependencyObject p) => p is Table || p == null;

Try / catch

try { table.RowGroups.Add(group); } catch (InvalidOperationException ex) when (ex.Message.Contains("parent")) { /* fix nesting */ }

Prevention

When it happens

Trigger: Adding a TableRowGroup to a non-Table container (e.g. a Grid, StackPanel children, or another TableRowGroup) or direct reparenting APIs with a non-Table parent.

Common situations: Confusing Table with Grid nesting; moving row groups between documents/trees with incompatible parents; XAML with TableRowGroup outside Table.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TableRowGroup.cs:289

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

        #region Private Methods

        /// <summary>
        /// Called when body receives a new parent (via OM or text tree)
        /// </summary>
        /// <param name="newParent">
        /// New parent of body
        /// </param>
        internal override void OnNewParent(DependencyObject newParent)
        {
            DependencyObject oldParent = this.Parent;

            if (newParent != null && !(newParent is Table))
            {
                throw new InvalidOperationException(SR.Format(SR.TableInvalidParentNodeType, newParent.GetType().ToString()));
            }

            if (oldParent != null)
            {
                OnExitParentTree();
                ((Table)oldParent).RowGroups.InternalRemove(this);
                OnAfterExitParentTree(oldParent as Table);
            }

            base.OnNewParent(newParent);

            if (newParent != null)
            {
                ((Table)newParent).RowGroups.InternalAdd(this);
                OnEnterParentTree();
            }
        }

View on GitHub (pinned to 81131a70a4)