dotnet/wpf · error · InvalidOperationException

SR.TypeMetadataCannotChangeAfterUse

Error message

SR.TypeMetadataCannotChangeAfterUse

What it means

PropertyMetadata.DefaultValue's setter throws InvalidOperationException when the metadata instance is Sealed, i.e. it has already been used to register a dependency property or otherwise sealed by the WPF property system. Metadata is frozen after first use so all registered properties share consistent behavior.

Solutions

  1. Create a new PropertyMetadata instance with the desired DefaultValue instead of mutating the sealed one.
  2. Use DependencyProperty.AddOwner or OverrideMetadata to supply new metadata for a derived type rather than editing existing metadata.
  3. Set DefaultValue in the constructor before any Register call, and keep metadata instances private per property.
  4. Check the Sealed property before mutating and branch to a fresh instance.

Example fix

// before
MyControl.ValueProperty.OverrideMetadata(typeof(MyControl), sharedMetadata);
sharedMetadata.DefaultValue = 42; // InvalidOperationException if sharedMetadata is sealed

// after
MyControl.ValueProperty.OverrideMetadata(typeof(MyControl),
    new PropertyMetadata { DefaultValue = 42 });
Defensive patterns

Strategy: validation

Validate before calling

if (metadata.Sealed)
    metadata = new PropertyMetadata { DefaultValue = newDefault };
else
    metadata.DefaultValue = newDefault;

Try / catch

try
{
    metadata.DefaultValue = newDefault;
}
catch (InvalidOperationException)
{
    // metadata already registered; use OverrideMetadata with a new instance instead
}

Prevention

When it happens

Trigger: Setting DefaultValue on a PropertyMetadata instance after it was passed to DependencyProperty.Register/RegisterAttached/RegisterReadOnly (or after Merge sealed it), typically via a shared/static metadata object.

Common situations: Reusing one static PropertyMetadata across multiple dependency properties and then mutating it; overriding defaults at runtime for a property that was already registered; framework code sealing metadata during app startup while later code mutates it.

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/5f37c32656ae6f5f. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/PropertyMetadata.cs:92

        public object DefaultValue
        {
            get
            {
                if (_defaultValue is not DefaultValueFactory defaultFactory)
                {
                    return _defaultValue;
                }
                else
                {
                    return defaultFactory.DefaultValue;
                }
            }

            set
            {
                if (Sealed)
                {
                    throw new InvalidOperationException(SR.TypeMetadataCannotChangeAfterUse);
                }

                if (value == DependencyProperty.UnsetValue)
                {
                    throw new ArgumentException(SR.DefaultValueMayNotBeUnset);
                }

                _defaultValue = value;

                SetModified(MetadataFlags.DefaultValueModifiedID);
            }
        }


        /// <summary>
        ///     Returns true if the default value is a DefaultValueFactory
        /// </summary>
        internal bool UsingDefaultValueFactory

View on GitHub (pinned to 81131a70a4)