stride3d/stride · error · InvalidOperationException
The asset directory cannot be null before deleting an asset.
Error message
The asset directory cannot be null before deleting an asset.
What it means
During batch asset deletion inside an undo/redo transaction, each asset must still belong to a directory. If an AssetViewModel's Directory is null when the delete loop reaches it, the editor's internal invariant is broken (the asset should always know its directory before deletion), so an InvalidOperationException is thrown to abort the operation rather than corrupt the session.
Solutions
- Ensure every asset has a valid Directory before invoking delete; re-attach or reload assets with a null Directory.
- Filter out (or fix) assets with null Directory before starting the delete loop: assets.Where(a => a.Directory != null).
- Refresh/rebuild the asset collection view model from the session to repair stale directory references.
Example fix
// before var toDelete = assets.ToList(); collectionViewModel.DeleteAssets(toDelete); // after var toDelete = assets.Where(a => a.Directory != null).ToList(); collectionViewModel.DeleteAssets(toDelete);
Defensive patterns
Strategy: validation
Validate before calling
if (assets.Any(a => a.Directory == null)) throw new InvalidOperationException("All assets must be attached to a directory before deletion"); Type guard
bool IsDeletable(AssetViewModel a) => a.Directory != null;
Try / catch
try { collection.DeleteAssets(assets); }
catch (InvalidOperationException ex) { logger.Error(ex, "Asset with null directory encountered during delete; refresh session"); } Prevention
- Never manipulate AssetViewModel.Directory directly outside undo transactions
- Refresh the collection view model after failed move/copy operations
- Pre-filter assets by Directory != null before batch operations
When it happens
Trigger: Calling the asset-collection delete operation (force or filtered by CanDelete) when one or more queued assets have had their Directory cleared or were created without being attached to a directory view model.
Common situations: Deleting assets that were just moved or unparented in a prior (possibly failed) transaction; assets whose parent directory was removed concurrently; session state corrupted by custom tooling that manipulates view models directly.
Related errors
- url cannot be null or empty.
- A category cannot be deleted
- Unable to find the base
- Unable to find the graph corresponding to the base part
- The base is unset for the current node.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/f786934a540c8d41.
Report an issue: GitHub.
Appendix: source
Thrown at sources/editor/Stride.Core.Assets.Editor/ViewModel/AssetCollectionViewModel.cs:443
UpdateAssetsCollection(newAssets, true);
}
/// <summary>
/// Deletes the given assets in a single transaction without asking for confirmation nor fixing broken references.
/// Assets whose <see cref="AssetViewModel.CanDelete()"/> method returns <c>false</c> won't be deleted, unless <paramref name="forceDelete"/> is <c>true</c>.
/// </summary>
/// <param name="assetsToDelete">The list of assets to delete.</param>
/// <param name="forceDelete">If <c>true</c> the asset whose <see cref="AssetViewModel.CanDelete()"/> method returns <c>false</c> will still be deleted</param>
/// <returns>The number of assets that have been successfully deleted.</returns>
internal int DeleteAssets(IEnumerable<AssetViewModel> assetsToDelete, bool forceDelete = false)
{
using (var transaction = Session.UndoRedoService.CreateTransaction())
{
var deletedAssets = new List<AssetViewModel>();
foreach (var asset in assetsToDelete.Where(x => forceDelete || x.CanDelete()))
{
if (asset.Directory == null)
throw new InvalidOperationException("The asset directory cannot be null before deleting an asset.");
if (!forceDelete && !asset.CanDelete())
continue;
// This must be done before we clear the Directory property of the asset
AssetDependenciesViewModel.NotifyAssetChanged(asset.Session, asset);
var oldDirectory = asset.Directory;
// It is important to set IsDeleted before clearing the directory, so the parent project can be marked as dirty
asset.IsDeleted = true;
asset.Directory.RemoveAsset(asset);
asset.Directory = null;
// Update RootAssets, for both current package and packages referencing this one
// Note: Package to Asset references should be handled in a more generic way (same as Asset to Asset references)
// We check only local
foreach (var localPackage in Session.LocalPackages)View on GitHub (pinned to 96fad776d2)