dotnet/wpf · error · InvalidOperationException

SR.Format(SR.TableInvalidParentNodeType…

Error message

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

What it means

TableRow.OnNewParent validates that a row's new parent is a TableRowGroup (or null). Assigning a TableRow to any other DependencyObject throws InvalidOperationException naming the offending type, since TableRow may only be parented by a TableRowGroup.

Solutions

  1. Add the TableRow to a TableRowGroup's Rows collection
  2. Fix XAML nesting: Table > TableRowGroup > TableRow > TableCell
  3. Guard reparenting code with 'newParent is TableRowGroup' before assignment

Example fix

// before
table.Rows.Add(row); // Table has RowGroups, not Rows
// after
var group = new TableRowGroup();
group.Rows.Add(row);
table.RowGroups.Add(group);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

static bool CanParentRow(DependencyObject p) => p is TableRowGroup || p == null;

Try / catch

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

Prevention

When it happens

Trigger: Reparenting a TableRow into a Table, TableCell, or arbitrary DependencyObject; adding a row to a collection other than TableRowGroup.Rows.

Common situations: Programmatic table construction with wrong nesting order; XAML placing TableRow directly under Table; refactor that swapped TableRowGroup for Table.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/TableRow.cs:89

        void IAddChild.AddText(string text)
        {
            XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this);
        }


        /// <summary>
        /// Called when tablerow gets new parent
        /// </summary>
        /// <param name="newParent">
        /// New parent of cell
        /// </param>
        internal override void OnNewParent(DependencyObject newParent)
        {
            DependencyObject oldParent = this.Parent;

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

            if (oldParent != null)
            {
                ((TableRowGroup)oldParent).Rows.InternalRemove(this);
            }

            base.OnNewParent(newParent);

            if (newParent != null)
            {
                ((TableRowGroup)newParent).Rows.InternalAdd(this);
            }
        }

        #endregion Public Methods

        //------------------------------------------------------

View on GitHub (pinned to 81131a70a4)