dotnet/wpf · error · InvalidOperationException
SR.Format(SR.PropertyIsImmutable, "DataType"…
Error message
SR.Format(SR.PropertyIsImmutable, "DataType", this.GetType().Name)
What it means
Within an initialization block, DataType may be set once; a second assignment to a different value throws InvalidOperationException with the PropertyIsImmutable message. Template keys hash and compare on DataType, so changing it after it is established would corrupt template lookup semantics.
Solutions
- Assign DataType exactly once per initialization block.
- Guard with 'if (key.DataType == null)' before assigning inside the initialization block.
- Instantiate a new TemplateKey for each distinct DataType.
Example fix
// before
key.BeginInit();
key.DataType = typeof(A);
key.DataType = typeof(B); // throws
// after
key.BeginInit();
if (key.DataType == null)
key.DataType = typeof(B);
key.EndInit(); Defensive patterns
Strategy: type-guard
Validate before calling
if (key.DataType != value)
{
key.BeginInit();
key.DataType = value;
key.EndInit();
} Type guard
bool CanAssign(TemplateKey key, object value) => key.DataType == null || key.DataType == value;
Try / catch
try { key.DataType = value; }
catch (InvalidOperationException ex) when (ex.Message.Contains("immutable")) { /* skip, already set */ } Prevention
- Assign each property at most once per initialization block.
- Centralize key construction in one factory method.
- Avoid generic property-copying that may double-assign DataType.
When it happens
Trigger: Calling BeginInit(), assigning DataType = typeof(A), then assigning DataType = typeof(B) before EndInit().
Common situations: Retry/reconfiguration loops that apply defaults then overwrite with the real value; generic property-setting frameworks that assign every property including already-set ones.
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
- SR.PropertyIsImmutable (formatted with "Prefix", type name)
- SR.PropertyIsImmutable (formatted with "Uri", type name)
- Cannot initialize compressor.
- Image_NeitherArgument (UriSource, StreamSource)
- SR.EndInitWithoutBeginInitNotSupported
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/7af19e67e74f177b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/TemplateKey.cs:71
_initializing = false;
}
#endregion ISupportInitialize
/// <summary>
/// The type for which the template is designed. This is either
/// a Type (for object data), or a string (for XML data). In the latter
/// case the string denotes the XML tag name.
/// </summary>
public object DataType
{
get { return _dataType; }
set
{
if (!_initializing)
throw new InvalidOperationException(SR.Format(SR.PropertyIsInitializeOnly, "DataType", this.GetType().Name));
if (_dataType != null && value != _dataType)
throw new InvalidOperationException(SR.Format(SR.PropertyIsImmutable, "DataType", this.GetType().Name));
Exception ex = ValidateDataType(value, "value");
if (ex != null)
throw ex;
_dataType = value;
}
}
/// <summary> Override of Object.GetHashCode() </summary>
public override int GetHashCode()
{
// note that the hash code can change, but only during intialization
// and only once (DataType can only be changed once, from null to
// non-null, and that can only happen during [Begin/End]Init).
// Technically this is still a violation of the "constant during
// lifetime" rule, however in practice this is acceptable. It is
// very unlikely that someone will put a TemplateKey into a hashtableView on GitHub (pinned to 81131a70a4)