dotnet/wpf · error · InvalidOperationException

SR.FrameworkElementFactoryMustBeSealed

Error message

SR.FrameworkElementFactoryMustBeSealed

What it means

InstantiateUnoptimizedTree is an internal entry point that requires the factory to be sealed; Seal() finalizes the factory tree (validates names, applies auto-alias rules) and is irreversible. If the factory was never sealed, the framework refuses to instantiate it and throws InvalidOperationException(SR.FrameworkElementFactoryMustBeSealed).

Solutions

  1. Call Seal() on the FrameworkElementFactory (or on the owning Template) before instantiation.
  2. Assign the factory to a DataTemplate/ControlTemplate (whose Seal will seal the factory) before using it.
  3. Ensure your template-building helper code finishes all factory mutations before the template's LoadContent is invoked, since Seal freezes the tree.

Example fix

// before
var template = new DataTemplate();
template.VisualTree = factory;
UIElement e = (UIElement)template.LoadContent(); // factory not sealed
// after
template.VisualTree = factory;
template.Seal();
UIElement e = (UIElement)template.LoadContent();
Defensive patterns

Strategy: validation

Validate before calling

// ensure the factory/template is sealed before instantiation
template.Seal(); // throws earlier with a clearer message if the tree is invalid

Type guard

null

Try / catch

try { template.LoadContent(); } catch (InvalidOperationException ex) when (ex.Message.Contains("sealed")) { template.Seal(); /* retry once */ }

Prevention

When it happens

Trigger: Internally calling InstantiateUnoptimizedTree (e.g. via template infrastructure or a host like DataTemplate/ControlTemplate instantiation) on a FrameworkElementFactory whose Seal() has not yet run — typically because the factory was constructed in code and never attached to a template or Seal() was not explicitly called.

Common situations: Building a FrameworkTemplate/DataTemplate programmatically with a factory but forgetting to seal before the template is requested; calling internal instantiation paths from custom framework plumbing; using the factory directly without ever assigning it to a Template property.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

                    throw new InvalidOperationException(SR.Format(SR.TypeMustImplementIAddChild,
                                                         parent.GetType().Name));
                }

                ((IAddChild)parent).AddChild(childFrameworkObject.DO);
            }
        }


        // This tree is used to instantiate a tree, represented by this factory.
        // It is instantiated as a normal tree without any template optimizations.
        // This is used by designers to inspect a template.

        internal FrameworkObject InstantiateUnoptimizedTree()
        {

            if (!_sealed)
            {
                throw new InvalidOperationException(SR.FrameworkElementFactoryMustBeSealed);
            }

            // Create the object.

            FrameworkObject frameworkObject = new FrameworkObject(CreateDependencyObject());

            // Mark the beginning of initialization

            frameworkObject.BeginInit();

            // Set values for this object, taking them from the shared values table.

            ProvideValueServiceProvider provideValueServiceProvider = null;
            FrameworkTemplate.SetTemplateParentValues( Name, frameworkObject.DO, _frameworkTemplate, ref provideValueServiceProvider );

            // Get the first child

            FrameworkElementFactory childFactory = _firstChild;

View on GitHub (pinned to 81131a70a4)