dotnet/wpf · error · InvalidOperationException
SR.Format(SR.TemplateMustBeFE, new object[] )
Error message
SR.Format(SR.TemplateMustBeFE, new object[] { rootObject.GetType().FullName }) What it means
WireRootObjectToParent requires the root object of a template's content to be a UIElement when the container is a FrameworkElement (so it can be assigned to TemplateChild). If the template's root XAML object is not a UIElement (e.g. a plain ContentElement or non-visual object), InvalidOperationException is thrown naming the root type.
Solutions
- Make the template's root element a UIElement-derived type (e.g. Grid, Border, StackPanel).
- Wrap non-visual content inside a visual container before returning it from the template.
- If content should be non-visual, ensure the template is applied in a content (not visual) position, or use a ContentPresenter.
Example fix
<!-- before --> <ControlTemplate TargetType="Button"><Run Text="hi"/></ControlTemplate> <!-- after --> <ControlTemplate TargetType="Button"><TextBlock Text="hi"/></ControlTemplate>
Defensive patterns
Strategy: validation
Validate before calling
if (!(rootObject is UIElement))
throw new InvalidOperationException($"Template root must be a UIElement, got {rootObject.GetType()}"); Type guard
static bool IsValidTemplateRoot(object o) => o is UIElement;
Try / catch
try { ApplyTemplate(t); } catch (InvalidOperationException ex) when (ex.Message.Contains("UIElement")) { /* fix template XAML */ } Prevention
- Always make template roots visual elements (Panel, Border, Control-derived).
- Test templates by instantiating them in a smoke test.
- Never put non-visual elements at the top of a ControlTemplate.
When it happens
Trigger: Defining a ControlTemplate/DataTemplate whose top-level element is not a UIElement (e.g. a Run, TextElement, or arbitrary CLR object) while the templated parent is a FrameworkElement.
Common situations: Hand-written or tool-mangled XAML where the root tag is wrong; wrapping content in a non-visual element by mistake; misunderstanding that template roots must be visual elements.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- SR.Animation_ChildMustBeKeyFrame
- SR.Animation_ChildMustBeKeyFrame
- SR.Animation_ChildMustBeKeyFrame
- SR.Animation_ChildMustBeKeyFrame
- SR.ChildHasWrongType (formatted with type name…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/fa2c636e0638e452.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkTemplate.cs:1122
}
InvalidatePropertiesOnTemplate(container, createdObject);
}
}
private static DependencyObject WireRootObjectToParent(object createdObject, DependencyObject rootObject, DependencyObject container, FrameworkElement feContainer, INameScope nameScope)
{
rootObject = createdObject as DependencyObject;
if (rootObject != null)
{
// Add the root to the appropriate tree.
if (feContainer != null)
{
// Put the root object into FE.Templatechild (must be a UIElement).
UIElement rootElement = rootObject as UIElement;
if (rootElement == null)
{
throw new InvalidOperationException(SR.Format(SR.TemplateMustBeFE, new object[] { rootObject.GetType().FullName }));
}
feContainer.TemplateChild = rootElement;
Debug.Assert(!(rootElement is FrameworkElement) ||
((FrameworkElement)rootElement).TemplateChildIndex != -1);
}
// If we have a container that is not a FE, add to the logical tree of the FEF
else if (container != null)
{
FrameworkElement feResult;
FrameworkContentElement fceResult;
Helper.DowncastToFEorFCE(rootObject, out feResult, out fceResult, true);
FrameworkElementFactory.AddNodeToLogicalTree((FrameworkContentElement)container,
rootObject.GetType(), feResult != null, feResult, fceResult);
}
// Set the TemplateNameScope on the rootView on GitHub (pinned to 81131a70a4)