stride3d/stride · error · InvalidOperationException
Model doesn't have expected parent.
Error message
Model doesn't have expected parent.
What it means
When a Model is removed from a Children collection, Model.Children_CollectionChangeeshanged verifies the child's parent is the collection's owner before clearing it. If child.parent does not match, the internal parent/child bookkeeping is inconsistent and InvalidOperationException is thrown.
Solutions
- Always add/remove children through the parent's Children collection and never set child.parent directly
- Ensure the child belongs to this parent before calling Remove (parent.Children.Contains(child))
- Re-add the child to the correct parent's collection so the bookkeeping is repaired before removing
Example fix
// before child.parent = newParent; // breaks invariants oldParent.Children.Remove(child); // throws // after oldParent.Children.Remove(child); // clears child.parent properly newParent.Children.Add(child);
Defensive patterns
Strategy: validation
Validate before calling
if (child.parent != this) return; // nothing to remove from this parent's bookkeeping parent.Children.Remove(child);
Type guard
static bool BelongsTo(Model child, Model owner) => child.parent == owner;
Try / catch
try { parent.Children.Remove(child); }
catch (InvalidOperationException ex) when (ex.Message == "Model doesn't have expected parent.") {
// bookkeeping corrupted; re-add to correct parent to repair
child.parent?.Children.Add(child);
} Prevention
- Mutate the hierarchy only through Children.Add/Remove
- Never assign child.parent manually
- After deserialization, rebuild parent links via Children rather than direct field writes
When it happens
Trigger: Removing a Model from a Children collection when its parent field points elsewhere — e.g. the child was manually re-parented, added to another collection, or its parent was changed without going through Children.
Common situations: Mixing manual parent manipulation with Children collection updates; stale removal after the child was moved; deserialization that sets parents directly then mutates collections.
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
- Model already have a parent.
- A PackageViewModel cannot contain two isntances of…
- A texture with size [ ] already exist with the same output…
- A transaction failed to be created.
- A UIPage asset can't have more than one root.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/ca108cf329721efc.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Rendering/Rendering/Model.cs:161
result.Skeleton = Skeleton;
result.BoundingBox = BoundingBox;
return result;
}
private void Children_CollectionChanged(object sender, TrackingCollectionChangedEventArgs e)
{
var child = (Model)e.Item;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (child.parent != null)
throw new InvalidOperationException("Model already have a parent.");
child.parent = this;
break;
case NotifyCollectionChangedAction.Remove:
if (child.parent != this)
throw new InvalidOperationException("Model doesn't have expected parent.");
child.parent = null;
break;
}
}
}
}
View on GitHub (pinned to 96fad776d2)