{"record":{"id":"a9d2a1206e6f233d","repo":"stride3d/stride","slug":"this-transformcomponent-s-parent-is-not-the-expected-value","errorCode":null,"errorMessage":"This TransformComponent's parent is not the expected value.","messagePattern":"This TransformComponent's parent is not the expected value\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Engine/Engine/TransformComponent.cs","lineNumber":367,"sourceCode":"            public TransformChildrenCollection(TransformComponent transformParam)\n            {\n                transform = transformParam;\n            }\n\n            private void OnTransformAdded(TransformComponent item)\n            {\n                if (item.Parent != null)\n                    throw new InvalidOperationException(\"This TransformComponent already has a Parent, detach it first.\");\n\n                item.parent = transform;\n\n                Entity?.EntityManager?.OnHierarchyChanged(item.Entity);\n                Entity?.EntityManager?.GetProcessor<TransformProcessor>().NotifyChildrenCollectionChanged(item, true);\n            }\n            private void OnTransformRemoved(TransformComponent item)\n            {\n                if (item.Parent != transform)\n                    throw new InvalidOperationException(\"This TransformComponent's parent is not the expected value.\");\n\n                item.parent = null;\n\n                Entity?.EntityManager?.OnHierarchyChanged(item.Entity);\n                Entity?.EntityManager?.GetProcessor<TransformProcessor>().NotifyChildrenCollectionChanged(item, false);\n            }\n\n            /// <inheritdoc/>\n            protected override void InsertItem(int index, TransformComponent item)\n            {\n                base.InsertItem(index, item);\n                OnTransformAdded(item);\n            }\n\n            /// <inheritdoc/>\n            protected override void RemoveItem(int index)\n            {\n                OnTransformRemoved(this[index]);","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Engine/Engine/TransformComponent.cs#L349-L385","documentation":"Thrown by TransformComponent.Children's OnTransformRemoved hook when removing a transform whose Parent does not match the transform that owns the collection. Mirrors the add-side check: the collection only removes transforms it actually parents. Hitting it means the child was reparented or its parent pointer changed out from under the collection.","triggerScenarios":"Calling transform.Children.Remove(item) / Clear / SetItem when item.Parent != transform — e.g. item was already detached and re-added elsewhere, or item.parent was nulled by a prior remove that threw mid-way.","commonSituations":"Double-detach in cleanup code (removing a child twice or from two different parents); scripts that set parent via a different collection then call Remove on the stale one; exception recovery paths leaving half-detached hierarchies.","solutions":["Guard with if (item.Parent == transform) before calling Remove; skip or log otherwise.","Remove the child from the parent that currently owns it (query item.Parent.Children.Remove(item)).","Avoid duplicated detach logic across code paths; centralize re-parenting in one helper that detaches once.","After a failed hierarchy operation, re-read Parent before retrying removal rather than assuming the old structure."],"exampleFix":"// before\nparent.Transform.Children.Remove(child.Transform); // throws if child.Parent != parent\n// after\nif (child.Transform.Parent == parent.Transform)\n    parent.Transform.Children.Remove(child.Transform);","handlingStrategy":"validation","validationCode":"bool canDetach(TransformComponent parent, TransformComponent child) => child.Parent == parent;","typeGuard":"bool IsOwnedBy(TransformComponent child, TransformComponent parent) => ReferenceEquals(child?.Parent, parent);","tryCatchPattern":"try { parentTransform.Children.Remove(childTransform); } catch (InvalidOperationException ex) { log.Warn($\"Child parent mismatch: {ex.Message}\"); }","preventionTips":["Check child.Parent == parent before Remove/Clear","Avoid double-detach paths; make detach idempotent with a guard","Track hierarchy ownership centrally to prevent stale references","After failures, re-read Parent before retrying"],"tags":["transform-hierarchy","invalid-state","stride"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}