dotnet/wpf · error · InvalidOperationException

SR.Format(SR.AlreadyHasLogicalChildren…

Error message

SR.Format(SR.AlreadyHasLogicalChildren, parent.GetType().Name)

What it means

AddNodeToLogicalTree, when the parent is a FrameworkContentElement, checks whether that parent already has logical children. Factory-built content is meant to become the sole logical child in this path; if the instantiated parent already enumerates at least one logical child, the framework throws InvalidOperationException(AlreadyHasLogicalChildren) naming the parent type, because it cannot unambiguously attach the factory node.

Solutions

  1. Clear the parent's existing content/children before applying the factory-built tree.
  2. Use a fresh, empty parent instance for the template instantiation.
  3. Restructure so the factory node is added through the parent's collection API rather than the single-logical-child path.

Example fix

// before
paragraph.Inlines.Add(existingRun);
template.LoadContent(); // factory node attach fails
// after
var freshParagraph = new Paragraph(); // empty parent for factory content
Defensive patterns

Strategy: validation

Validate before calling

if (parent is FrameworkContentElement fce && fce.LogicalChildren != null && fce.LogicalChildren.MoveNext())
    throw new InvalidOperationException($"{fce.GetType().Name} already has logical children; use an empty parent");

Type guard

bool IsEmptyLogicalParent(FrameworkContentElement e) { var it = e.LogicalChildren; return it == null || !it.MoveNext(); }

Try / catch

try { template.LoadContent(); } catch (InvalidOperationException ex) when (ex.Message.Contains("logical children")) { /* clear content or create fresh parent */ }

Prevention

When it happens

Trigger: Instantiating a factory tree where a FrameworkContentElement node (e.g. a Paragraph or another content element) already has children — for example a control whose content was set earlier — and AddNodeToLogicalTree then attempts to attach the factory-built node.

Common situations: Reusing a pre-populated control instance as a template root; template content applied over an element whose Content/Children were already populated by prior code; FlowDocument content elements with existing inlines used inside generated templates.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkElementFactory.cs:1111

        /// it is actually added to the logical tree because FrameworkContentElement
        /// has no visual tree.
        /// </summary>
        /// <remarks>
        ///     A prime example of trying to shove a square peg into a round hole.
        /// </remarks>
        internal static void AddNodeToLogicalTree( DependencyObject parent, Type type,
            bool treeNodeIsFE, FrameworkElement treeNodeFE, FrameworkContentElement treeNodeFCE)
        {
            // If the logical parent already has children, then we can't add
            // a logical subtree from the style, since there would be a conflict.
            // Throw an exception in this case.
            FrameworkContentElement logicalParent = parent as FrameworkContentElement;
            if (logicalParent != null)
            {
                IEnumerator childEnumerator = logicalParent.LogicalChildren;
                if (childEnumerator != null && childEnumerator.MoveNext())
                {
                    throw new InvalidOperationException(SR.Format(SR.AlreadyHasLogicalChildren,
                                                          parent.GetType().Name));
                }
            }

            IAddChild  addChildParent = parent as IAddChild;
            if (addChildParent == null)
            {
                throw new InvalidOperationException(SR.Format(SR.CannotHookupFCERoot,
                                                          type.Name));
            }
            else
            {
                if (treeNodeFE != null)
                {
                    addChildParent.AddChild(treeNodeFE);
                }
                else
                {

View on GitHub (pinned to 81131a70a4)