stride3d/stride · error · InvalidOperationException
PropertyChanged is invoked without PropertyChanging, or…
Error message
PropertyChanged is invoked without PropertyChanging, or multiple items in the collection are changing concurrently.
What it means
ItemPropertyChanged validates that a PropertyChanged notification is matched by a prior PropertyChanging for the same item. If both ChangingItem and AddedItem are set (a new item was added while another item reports a property change) the tracking state is inconsistent, so it throws. This can also fire when PropertyChanged arrives with no PropertyChanging at all.
Solutions
- Raise PropertyChanging before every PropertyChanged for the same property on the same object (use SetProperty/PropertyChangedBase helpers)
- Do not add items to the collection while another item's property change is in flight
- Fix the item class's INotifyPropertyChanged ordering (Changing first, then Changed)
- Verify all item types derive from a base implementing correct change-notification pairs
Example fix
// before
public string Name
{
get => name;
set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); }
}
// after
public string Name
{
get => name;
set
{
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Name)));
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
} Defensive patterns
Strategy: validation
Validate before calling
// Verify item types raise Changing before Changed: raiseChanging(name); value = x; raiseChanged(name);
Try / catch
try { collection.Add(item); } catch (InvalidOperationException ex) { logger.Error(ex, "unmatched PropertyChanged"); } Prevention
- Derive items from a base implementing correct Changing/Changed pairing (e.g. PropertyChangedBase)
- Never raise PropertyChanged without PropertyChanging for the same property
- Do not Add items to the collection inside another item's property-change scope
When it happens
Trigger: An item raising PropertyChanged without ever raising PropertyChanging; an item added to the collection inside another item's property-change scope; mis-ordered raise calls in a SetProperty helper.
Common situations: Hand-written setters that only raise PropertyChanged; adding items inside a property setter; third-party view-models with incomplete INotifyPropertyChanged implementations used as collection items.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Multiple items in the collection are changing concurrently.
- The list must implements INotifyPropertyChanged
- An element with the same key has already been added.
- An id is both marked as deleted and associated to a key of…
- An item has been added to a collection that does not have a…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/2dba06a8a2371959.
Report an issue: GitHub.
Appendix: source
Thrown at sources/presentation/Stride.Core.Presentation/Collections/AutoUpdatingSortedObservableCollection.cs:132
throw new InvalidOperationException("Multiple items in the collection are changing concurrently.");
++changeCount;
ChangingItem = item;
ChangingIndex = GetIndex(item, false);
AddedItem = null;
}
protected virtual void ItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName is null || propertyNames?.Contains(e.PropertyName) == false)
return;
var item = (T?)sender;
// An object has been added while a property of an existing object has been modified
if (ChangingItem is not null && AddedItem is not null)
throw new InvalidOperationException("PropertyChanged is invoked without PropertyChanging, or multiple items in the collection are changing concurrently.");
// The object has been added to the collection during the property change, so it was not preregistered by the ItemPropertyChanging event
if (ChangingItem is null && AddedItem is not null)
{
ChangingItem = AddedItem;
ChangingIndex = AddedIndex;
++changeCount;
}
// No object is changing, or a different object is currently changing
if (ChangingItem is null || !ReferenceEquals(ChangingItem, item))
{
throw new InvalidOperationException("PropertyChanged is invoked without PropertyChanging, or multiple items in the collection are changing concurrently.");
}
--changeCount;
if (changeCount == 0)
{View on GitHub (pinned to 96fad776d2)