stride3d/stride · error · InvalidOperationException

InvalidOperationException

Error message

InvalidOperationException

What it means

SceneViewModel.ChildrenNodeItemChanged reacts to changes of the underlying childrenNode identifier collection. Only CollectionUpdate, CollectionAdd and CollectionRemove change types are supported; ContentChangeType.None and ContentChangeType.ValueChange indicate a change type that should never occur on a collection node, so the handler throws InvalidOperationException to flag a broken internal invariant.

Solutions

  1. Mutate childrenNode through its collection API (Add/Remove/Insert) instead of reassigning the property reference.
  2. If reassignment is unavoidable, guard the change with updatingChildren (or an undo/redo transaction) so the handler skips it.
  3. Extend ChildrenNodeItemChanged to handle ValueChange by rebuilding Children from the new child-id list.

Example fix

// before
scene.childrenNode = newChildIds; // raises ValueChange -> InvalidOperationException
// after
scene.childrenNode.Clear();
foreach (var id in newChildIds)
    scene.childrenNode.Add(id);
Defensive patterns

Strategy: try-catch

Validate before calling

if (e.ChangeType is ContentChangeType.None or ContentChangeType.ValueChange)
    return; // not a collection-level change; handle or skip

Type guard

static bool IsCollectionChange(ContentChangeType t) =>
    t is ContentChangeType.CollectionUpdate or ContentChangeType.CollectionAdd or ContentChangeType.CollectionRemove;

Try / catch

try
{
    MutateChildrenViaCollectionApi();
}
catch (InvalidOperationException)
{
    // property was reassigned instead of mutated; rebuild Children from childrenNode
    RebuildChildrenFromIds();
}

Prevention

When it happens

Trigger: A ValueChange or None event raised on the childrenNode member node (e.g. the whole childrenNode property being replaced rather than mutated as a collection) while updatingChildren is false.

Common situations: Undo/redo or serialization code assigning a new list to the childrenNode property instead of adding/removing entries, triggering a value-level change event on a collection that only supports item-level events.

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 stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/63ec70833f8cc95b. Report an issue: GitHub.

Appendix: source

Thrown at sources/editor/Stride.Assets.Presentation/ViewModel/SceneViewModel.cs:322

                        {
                            childId = (AssetId)e.OldValue;
                            childScene = (SceneViewModel)Session.GetAssetById(childId);
                            childScene.Parent = null;
                            Children.Remove(childScene);
                        }
                        if (e.NewValue != null)
                        {
                            childId = (AssetId)e.NewValue;
                            childScene = (SceneViewModel)Session.GetAssetById(childId);
                            childScene.Parent?.Children.Remove(childScene);
                            childScene.Parent = this;
                            Children.Insert(e.Index.Int, childScene);
                        }
                        break;

                    case ContentChangeType.None:
                    case ContentChangeType.ValueChange:
                        throw new InvalidOperationException();
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
            finally
            {
                updatingChildren = false;
            }
        }

        private void ParentNodeValueChanged(object sender, MemberNodeChangeEventArgs e)
        {
            if (updatingParent)
                return;

            try
            {
                updatingParent = true;

View on GitHub (pinned to 96fad776d2)