dotnet/wpf · error · InvalidOperationException
SR.LocalValueEnumerationInvalidated
Error message
SR.LocalValueEnumerationInvalidated
What it means
Thrown by SetEffectiveValue when the DependencyObject's effective-value table cannot be modified because an enumeration over LocalValueDictionary is in progress (CanModifyEffectiveValues == false). Modifying local values during that enumeration would corrupt the enumerator, so the property system blocks it.
Solutions
- Snapshot the enumerated entries (ToList()/ToArray()) first, then modify values after the loop ends
- Defer SetValue/ClearValue via Dispatcher.BeginInvoke if changes must happen during enumeration
- Restructure code so enumeration and mutation target different DependencyObjects
- Lock or single-thread the mutation path to avoid re-entrancy
Example fix
// before
foreach (var e in obj.ReadLocalValues()) { obj.ClearValue(e.Key); } // throws
// after
foreach (var e in obj.ReadLocalValues().ToList()) { obj.ClearValue(e.Key); } Defensive patterns
Strategy: try-catch
Validate before calling
if (!obj.CanModifyEffectiveValues) {
pendingChanges.Add(() => obj.SetValue(dp, value)); // defer
} else { obj.SetValue(dp, value); } Try / catch
try { obj.SetValue(dp, value); }
catch (InvalidOperationException) when (isEnumeratingLocalValues) { obj.Dispatcher.BeginInvoke(() => obj.SetValue(dp, value)); } Prevention
- Never call SetValue/ClearValue inside foreach over ReadLocalValues
- Snapshot enumerations with ToList/ToArray first
- Defer mutations triggered during enumeration via Dispatcher or a queue
When it happens
Trigger: Calling SetValue/ClearValue on a DependencyObject from inside a foreach over its ReadLocalValues / LocalValueDictionary on the same object; re-entrant property changes triggered from a local-value enumerator callback.
Common situations: Iterating local values to reset them and clearing inside the loop, diagnostics/logging code enumerating values while bindings update them, re-entrancy from value-change handlers fired during enumeration.
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_CalculatedValueIsInvalidForProperty
- Animation_DependencyPropertyIsNotAnimatable
- InvalidOperationException()
- NotImplementedException
- SR.Animation_DependencyPropertyIsNotAnimatable
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/5157bca64d0ced40.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyObject.cs:3114
return new EntryIndex(iLo, found: false);
}
// insert the given entry at the given index
// this function assumes that entryIndex is at the right
// location such that the resulting list remains sorted by EffectiveValueEntry.PropertyIndex
private void InsertEntry(EffectiveValueEntry entry, uint entryIndex)
{
// For thread-safety, sealed DOs can't modify _effectiveValues.
Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified");
#if DEBUG
EntryIndex debugIndex = LookupEntry(entry.PropertyIndex);
Debug.Assert(!debugIndex.Found && debugIndex.Index == entryIndex, "Inserting duplicate");
#endif
if (!CanModifyEffectiveValues)
{
throw new InvalidOperationException(SR.LocalValueEnumerationInvalidated);
}
uint effectiveValuesCount = EffectiveValuesCount;
if (effectiveValuesCount > 0)
{
if (_effectiveValues.Length == effectiveValuesCount)
{
int newSize = (int) (effectiveValuesCount * (IsInPropertyInitialization ? 2.0 : 1.2));
if (newSize == effectiveValuesCount)
{
newSize++;
}
EffectiveValueEntry[] destEntries = new EffectiveValueEntry[newSize];
Array.Copy(_effectiveValues, 0, destEntries, 0, entryIndex);
destEntries[entryIndex] = entry;
Array.Copy(_effectiveValues, entryIndex, destEntries, entryIndex + 1, effectiveValuesCount - entryIndex);
_effectiveValues = destEntries;View on GitHub (pinned to 81131a70a4)