dotnet/wpf · error · IOException
SR.CanNotDeleteNonEmptyStorage
Error message
SR.CanNotDeleteNonEmptyStorage
What it means
Thrown by StorageInfo.Delete when the storage still contains child storages or streams and recursive=false. The compound file refuses to destroy a non-empty element unless the caller explicitly asks for recursive deletion, preventing accidental data loss inside the package.
Solutions
- Pass recursive: true to Delete when intentional full removal is wanted
- Check StorageIsEmpty() first and decide what to do with children
- Enumerate and delete children (streams and sub-storages) explicitly before calling Delete
- Ensure prior write steps actually consumed/emptied the storage before cleanup
Example fix
// before storage.Delete(); // after storage.Delete(recursive: true); // or check storage.StorageIsEmpty() first
Defensive patterns
Strategy: validation
Validate before calling
if (!storage.StorageIsEmpty() && !recursive)
throw new InvalidOperationException("Refusing to delete non-empty storage without recursive"); Try / catch
try { storage.Delete(recursive); }
catch (IOException ex) { /* storage non-empty: enumerate children or request recursive */ } Prevention
- Decide explicitly whether deletion should be recursive
- Check StorageIsEmpty() before non-recursive Delete
- Verify cleanup expectations: intermediate storages may have been repopulated
When it happens
Trigger: Calling Delete() (non-recursive) on a storage that has children; deleting a '\u0006DataSpaces' or TransformInfo storage that still contains streams.
Common situations: Cleanup code assuming storages are empty; incremental package writers removing intermediate storages that were reused and repopulated; deleting a page/fragment storage with content still inside.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- ' ' name is already in use.
- SR.CanNotDeleteInReadOnly
- SR.CanNotDeleteRoot
- SR.StorageAlreadyExist
- SR.StorageNotExist
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/e6bd1d37e2484f9f.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageInfo.cs:701
/// </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.
return storageDeleted;
}
/// <summary>
/// When a substorage is getting deleted, its references in the dataspacemanager's transform definition are removed.
/// This is called recursively because the DeleteSubStorage deletes all its children by default.
/// </summary>
internal void RemoveSubStorageEntryFromDataSpaceMap(StorageInfo storageInfo)View on GitHub (pinned to 81131a70a4)