{"record":{"id":"f33c6628a7427134","repo":"stride3d/stride","slug":"a-category-cannot-be-deleted","errorCode":null,"errorMessage":"A category cannot be deleted","messagePattern":"A category cannot be deleted","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/editor/Stride.Core.Assets.Editor/ViewModel/CategoryViewModel.cs","lineNumber":41,"sourceCode":"        {\n            Name = name;\n            Content = new SortedObservableCollection<TChildren>(childComparer);\n        }\n\n        public sealed override string Name { get; set; }\n\n        public SortedObservableCollection<TChildren> Content { get; }\n\n        public override bool IsEditable => false;\n\n        IEnumerable ICategoryViewModel.Content => Content;\n\n        public override string TypeDisplayName => \"Category\";\n\n        protected override void UpdateIsDeletedStatus()\n        {\n            if (IsDeleted)\n                throw new InvalidOperationException(\"A category cannot be deleted\");\n        }\n    }\n\n    public abstract class CategoryViewModel<TParent, TChildren> : CategoryViewModel<TChildren>\n    {\n        protected CategoryViewModel(string name, TParent parent, SessionViewModel session, IComparer<TChildren> childComparer = null)\n            : base(name, session, childComparer)\n        {\n            Parent = parent;\n        }\n\n        public TParent Parent { get; }\n    }\n\n    public class PackageCategoryViewModel : CategoryViewModel<PackageViewModel>, IChildViewModel\n    {\n        public PackageCategoryViewModel(string name, SessionViewModel session, IComparer<PackageViewModel> childComparer = null)\n            : base(name, session, childComparer)","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/editor/Stride.Core.Assets.Editor/ViewModel/CategoryViewModel.cs#L23-L59","documentation":"CategoryViewModel represents an organizational category node in the asset tree, not a deletable entity. Its UpdateIsDeletedStatus override throws InvalidOperationException if something marks it as deleted. This is an internal invariant: only leaf items can be deleted, categories are structural nodes.","triggerScenarios":"Invoking delete logic on a CategoryViewModel — e.g. generic delete handlers that iterate all selected tree nodes including categories, or code setting IsDeleted on a category.","commonSituations":"Selecting a whole category in the editor and pressing Delete; batch-deletion scripts that do not filter tree-node types.","solutions":["Filter selection to deletable item view models before deleting; skip nodes whose IsEditable/CanDelete indicates a category.","Handle CanDelete returning false instead of forcing delete on category nodes.","Call delete operations only on concrete asset/directory view models, not on CategoryViewModel instances."],"exampleFix":"// before\nforeach (var node in selectedNodes) node.Delete();\n// after\nforeach (var node in selectedNodes.OfType<AssetViewModel>()) node.Delete();","handlingStrategy":"validation","validationCode":"if (node is CategoryViewModel) { logger.Info(\"Categories cannot be deleted\"); return; }","typeGuard":"bool IsDeletableNode(object node) => node is not CategoryViewModel;","tryCatchPattern":"try { node.Delete(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"category\")) { logger.Warn(\"Cannot delete a category node; delete its items instead\"); }","preventionTips":["Filter tree selections to item view models before delete operations","Respect CanDelete(out error) results instead of forcing deletion","Design delete UI to disable the action on category nodes"],"tags":["assets","category-node","delete-operation","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}