{"record":{"id":"55d87de15683cb4f","repo":"stride3d/stride","slug":"this-transformcomponent-already-has-a-parent-detach-it-first","errorCode":null,"errorMessage":"This TransformComponent already has a Parent, detach it first.","messagePattern":"This TransformComponent already has a Parent, detach it first\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Engine/Engine/TransformComponent.cs","lineNumber":357,"sourceCode":"                transformOperation.Process(this);\n            }\n        }\n\n        [DataContract]\n        public class TransformChildrenCollection : FastCollection<TransformComponent>\n        {\n            TransformComponent transform;\n            Entity Entity => transform.Entity;\n\n            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/>","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Engine/Engine/TransformComponent.cs#L339-L375","documentation":"Thrown by TransformComponent.Children collection's OnTransformAdded hook when a transform that still has a Parent is inserted into another transform's children. A TransformComponent can only belong to one parent at a time; the caller must detach it first. This keeps the transform hierarchy single-parented so world matrices stay well defined.","triggerScenarios":"Calling transform.Children.Add(otherTransform) (or an indexer insert/set that routes through InsertItem/SetItem) while otherTransform.Parent != null — e.g. re-parenting an entity's TransformComponent without removing it from its previous parent's children.","commonSituations":"Runtime entity re-parenting scripts that forget to detach; dragging entities between parents in the editor via custom tooling; reusing pooled entity hierarchies whose transforms were not reset.","solutions":["Detach first: call transform.Children.Remove(item) on the current parent, or set the old parent's collection to drop it, before adding to the new parent.","Check item.Parent == null before adding; if not, remove from the current parent.","Prefer entity-level APIs (Entity transformation/parent assignment) that handle detach/add atomically instead of touching TransformComponent.Children directly.","When reusing pooled hierarchies, reset parent links (item.parent) before re-attaching."],"exampleFix":"// before\nnewParent.Transform.Children.Add(child.Transform); // throws if still parented\n// after\nif (child.Transform.Parent != null)\n    child.Transform.Parent.Children.Remove(child.Transform);\nnewParent.Transform.Children.Add(child.Transform);","handlingStrategy":"validation","validationCode":"bool canAttach(TransformComponent newParent, TransformComponent child) => child.Parent == null && newParent != child;","typeGuard":"bool IsDetached(TransformComponent t) => t?.Parent == null;","tryCatchPattern":"try { parentTransform.Children.Add(childTransform); } catch (InvalidOperationException ex) { log.Error($\"{childTransform.Entity?.Name} still parented: {ex.Message}\"); }","preventionTips":["Always detach (Remove from current parent) before re-parenting","Guard with child.Parent == null check before Add","Prefer entity-level parenting APIs over raw TransformComponent.Children edits","Reset pooled hierarchies' parent links on reuse"],"tags":["transform-hierarchy","reparenting","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"}