dotnet/wpf · error · InvalidOperationException
SR.Format(SR.CannotChangeAfterSealed…
Error message
SR.Format(SR.CannotChangeAfterSealed, "FrameworkElementFactory")
What it means
FrameworkElementFactory becomes sealed (immutable) once it is used to create a template instance. Attempting to set the Type property afterwards throws InvalidOperationException(SR.CannotChangeAfterSealed, "FrameworkElementFactory"). All configuration must happen before the factory is compiled into a template and instantiated.
Solutions
- Create a new FrameworkElementFactory for each template (re)definition instead of reusing a sealed one
- Perform all factory configuration (Type, properties, children) immediately after construction, before attaching to a template
- Cache the DataTemplate, not the mutable factory, and rebuild factories when configuration changes
- Check factory.IsSealed before mutating to fail fast in debug builds
Example fix
// before static FrameworkElementFactory factory = Build(); // later factory.FactoryType = typeof(Button); // throws when sealed // after var factory = new FrameworkElementFactory(typeof(Button)); // fresh instance per template template.VisualTree = factory;
Defensive patterns
Strategy: validation
Validate before calling
if (factory.IsSealed) throw new InvalidOperationException("FrameworkElementFactory is sealed; create a new one"); Type guard
bool CanMutateFactory(FrameworkElementFactory f) => !f.IsSealed;
Try / catch
try { factory.FactoryType = typeof(Button); }
catch (InvalidOperationException) { factory = new FrameworkElementFactory(typeof(Button)); } Prevention
- Treat factories as build-once, use-once
- Never cache shared FrameworkElementFactory instances in static fields
- Cache the DataTemplate and rebuild factories on config change
When it happens
Trigger: Setting FactoryType (or other properties) on a FrameworkElementFactory after a template that uses it has been sealed — i.e. after the template was applied/compiled and instances created.
Common situations: Mutating a shared factory cached in a static field after first use; changing factory Type in code after assigning it to a DataTemplate/ControlTemplate; hot-swapping template definitions at runtime without creating fresh factories.
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
- Animation_Invalid_DefaultValue
- Cannot remove signature from read-only file.
- Image_EncoderNoColorContext
- Image_EncoderNoGlobalMetadata
- Image_EncoderNoGlobalThumbnail
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9390f4fddfcacdb0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/FrameworkElementFactory.cs:72
/// <param name="name">Style identifier</param>
public FrameworkElementFactory(Type type, string name)
{
Type = type;
Name = name;
}
/// <summary>
/// Type of object that the factory will produce
/// </summary>
public Type Type
{
get { return _type; }
set
{
if (_sealed)
{
throw new InvalidOperationException(SR.Format(SR.CannotChangeAfterSealed, "FrameworkElementFactory"));
}
if (_text != null)
{
throw new InvalidOperationException(SR.FrameworkElementFactoryCannotAddText);
}
if ( value != null ) // We allow null up until Seal
{
// If non-null, must be derived from one of the supported types
if (!typeof(FrameworkElement).IsAssignableFrom(value) &&
!typeof(FrameworkContentElement).IsAssignableFrom(value) &&
!typeof(Visual3D).IsAssignableFrom(value))
{
throw new ArgumentException(SR.Format(SR.MustBeFrameworkOr3DDerived, value.Name));
}
}
View on GitHub (pinned to 81131a70a4)