{"record":{"id":"e15c74f95fa178a5","repo":"stride3d/stride","slug":"a-uipage-asset-can-t-have-more-than-one-root","errorCode":null,"errorMessage":"A UIPage asset can't have more than one root.","messagePattern":"A UIPage asset can't have more than one root\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/editor/Stride.Assets.Presentation/AssetEditors/UIPageEditor/ViewModels/UIPageRootViewModel.cs","lineNumber":77,"sourceCode":"                message = \"Empty selection\";\n                return false;\n            }\n\n            if (count == 1)\n                return true;\n\n            message = OneRootOnly;\n            return false;\n        }\n\n        /// <inheritdoc />\n        protected override void OnRootUIElementsChanged(ItemChangeEventArgs e)\n        {\n            switch (e.ChangeType)\n            {\n                case ContentChangeType.CollectionAdd:\n                    if (UIAsset.Hierarchy.RootParts.Count != 1)\n                        throw new InvalidOperationException(OneRootOnly);\n                    Editor.ActiveRoot = RootElement;\n                    break;\n\n                case ContentChangeType.CollectionRemove:\n                    if (UIAsset.Hierarchy.RootParts.Count != 0)\n                        throw new InvalidOperationException(OneRootOnly);\n                    break;\n            }\n        }\n\n        void IAddChildViewModel.AddChildren(IReadOnlyCollection<object> children, AddChildModifiers modifiers)\n        {\n            if (children.Count != 1)\n                return;\n\n            if (RootElement != null)\n            {\n                ((IAddChildViewModel)RootElement).AddChildren(children, modifiers);","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/editor/Stride.Assets.Presentation/AssetEditors/UIPageEditor/ViewModels/UIPageRootViewModel.cs#L59-L95","documentation":"Thrown by UIPageRootViewModel.OnRootUIElementsChanged (CollectionAdd branch) when adding a root element would leave the UIPage with a root-parts count other than 1. A UIPage asset is constrained to exactly one root UI element, so the second addition violates the invariant.","triggerScenarios":"Calling AddChildren / adding an element while the page already has a root, making Hierarchy.RootParts.Count != 1 after the add; programmatic insertion of a second root part into RootParts.","commonSituations":"Dragging a new element onto the page canvas when one already exists; scripted asset manipulation appending extra root parts; import tools creating multiple top-level elements.","solutions":["Remove or merge the existing root before adding a new one, or replace it via ReplaceRootElement.","Nest the new element under the existing root instead of adding it as a second root.","Validate RootParts.Count == 0 before adding a new root programmatically."],"exampleFix":"// before\npageAsset.Hierarchy.RootParts.Add(newPart); // second root\n// after\nif (pageAsset.Hierarchy.RootParts.Count > 0)\n    pageAsset.Hierarchy.RootParts[0].Children.Add(newPart); // nest instead\nelse\n    pageAsset.Hierarchy.RootParts.Add(newPart);","handlingStrategy":"validation","validationCode":"bool canAddRoot = pageAsset.Hierarchy.RootParts.Count == 0;","typeGuard":"static bool CanAddRoot(UIAssetBase page) => page.Hierarchy.RootParts.Count == 0;","tryCatchPattern":"try { editor.AddChildren(newElements, modifiers); } catch (InvalidOperationException ex) { /* nest under existing root instead */ }","preventionTips":["Check RootParts.Count before adding root elements.","Use ReplaceRootElement to swap roots rather than adding a second one.","Nest new elements under the existing root by default."],"tags":["stride","ui-page","single-root","invariant"],"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-16T04:17:20.429Z"}