dotnet/wpf · error · InvalidOperationException

SR.CanNotDeleteRoot

Error message

SR.CanNotDeleteRoot

What it means

Thrown by StorageInfo.Delete when attempting to delete the root storage of a compound file. The root storage has no parent (parentStorage is null), so 'deleting' it is meaningless and would leave the file object in an invalid state; the library raises InvalidOperationException to indicate a caller logic error.

Solutions

  1. Only call Delete on non-root storages (check parentStorage != null)
  2. Delete individual child storages/streams instead of the root; to clear a file, delete children or overwrite the file
  3. Guard recursive cleanup with an isRoot check before invoking Delete
  4. Close and delete the whole file at the filesystem level if the intent is to remove the package entirely

Example fix

// before
foreach (var s in storages) s.Delete(true); // storages includes root
// after
foreach (var s in storages.Where(s => s != root)) s.Delete(true);
Defensive patterns

Strategy: type-guard

Validate before calling

if (storage.parentStorage == null) throw new InvalidOperationException("Cannot delete the root storage");

Type guard

bool IsRoot(StorageInfo s) => s.parentStorage == null; // skip roots in delete loops

Try / catch

try { storage.Delete(recursive); }
catch (InvalidOperationException ex) { /* root deletion attempt: skip or rethrow */ }

Prevention

When it happens

Trigger: Calling Delete() or Delete(name) on the StorageRoot/root StorageInfo instance obtained from StorageRoot.OpenOnFile/OpenOnStream.

Common situations: Recursive cleanup code that walks a storage tree and deletes children but recurses into or mis-targets the root; generic 'delete everything' helpers that pass the root node.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/c62dc88136690784. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageInfo.cs:693

        }
    
        // Return a reference
        return newSubStorage;
    }
    
    /// <summary>
    /// Deletes a storage, recursively if specified.
    /// </summary>
    /// <param name="recursive">Whether to recursive delete all existing content</param>
    /// <param name="name">Name of storage</param>
    internal bool Delete( bool recursive , string name)
    {
        bool storageDeleted = false;
        CheckDisposedStatus();
        if( null == parentStorage )
        {
            // We are the root storage, you can't "delete" the root storage!
            throw new InvalidOperationException(
                SR.CanNotDeleteRoot);
        }

        if( InternalExists(name) )
        {
            if( !recursive && !StorageIsEmpty())
            {
                throw new IOException(
                    SR.CanNotDeleteNonEmptyStorage);
            }

            InvalidateEnumerators();
            // Go ahead and delete "this" storage
            parentStorage.DestroyElement( name );
            storageDeleted = true;
        }
        //We will not throw exceptions if the storage does not exist. This is to be consistent with Package.DeletePart.
        

View on GitHub (pinned to 81131a70a4)