stride3d/stride · error · InvalidOperationException

System packages cannot be deleted.

Error message

System packages cannot be deleted.

What it means

PackageViewModel.Delete removes a package from the session, but system/read-only packages (Package.IsReadOnly) are protected. It throws InvalidOperationException because deleting such packages would break the loaded project's system dependencies.

Solutions

  1. Check Package.IsReadOnly before calling Delete and skip read-only packages
  2. Remove the package from user-editable selections
  3. Only delete packages that are direct user dependencies

Example fix

// before
packageViewModel.Delete();
// after
if (!packageViewModel.Package.IsReadOnly) packageViewModel.Delete();
Defensive patterns

Strategy: validation

Validate before calling

if (packageViewModel.Package.IsReadOnly) throw new InvalidOperationException("System packages cannot be deleted");

Type guard

bool CanDelete(PackageViewModel p) => !p.Package.IsReadOnly;

Try / catch

try { p.Delete(); } catch (InvalidOperationException) { /* read-only system package */ }

Prevention

When it happens

Trigger: Calling Delete() on a PackageViewModel whose Package.IsReadOnly is true — e.g. a system package like Stride core assets.

Common situations: Selecting a system package in the solution explorer and deleting it; bulk-delete operations that include read-only packages.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/e30b7a66b19d4e26. Report an issue: GitHub.

Appendix: source

Thrown at sources/editor/Stride.Core.Assets.Editor/ViewModel/PackageViewModel.cs:380

        }

        private static bool CheckDependsOnRecursively(PackageViewModel source, PackageViewModel target, List<PackageViewModel> visitedPackages)
        {
            visitedPackages.Add(source);
            return source.Dependencies.Content.Any(x => x.Target == target) || source.Dependencies.Content.Select(x => x.Target).NotNull().Where(x => !visitedPackages.Contains(x)).Any(x => CheckDependsOnRecursively(x, target, visitedPackages));
        }

        public void MoveAsset(AssetViewModel asset, DirectoryBaseViewModel directory)
        {
            asset.MoveAsset(Package, directory);
        }

        public void Delete()
        {
            if (Package.IsReadOnly)
            {
                // Note: this should never happen (see comments in method SessionViewModel.DeleteSelectedSolutionItems)
                throw new InvalidOperationException("System packages cannot be deleted.");
            }
            using (var transaction = UndoRedoService.CreateTransaction())
            {
                string message = $"Delete package '{Name}'";
                IsDeleted = true;
                UndoRedoService.SetName(transaction, message);
            }
        }

        public void CheckConsistency()
        {
            // Only compare referenceable assets: non-referenceable ones (e.g. scripts) are indexed
            // differently and must be filtered on both sides, otherwise they always appear inconsistent.
            static bool IsReferenceable(Asset asset) => asset.GetType().GetCustomAttribute<AssetDescriptionAttribute>()?.Referenceable ?? true;

            var assetList = Package.Assets.Where(item => IsReferenceable(item.Asset)).ToDictionary(x => x.Location.FullPath);
            var assetViewModels = Assets.Where(x => IsReferenceable(x.AssetItem.Asset)).ToList();
            var logger = Session.AssetLog.GetLogger(LogKey.Get("Consistency"));

View on GitHub (pinned to 96fad776d2)