dotnet/wpf · error · IOException

SR.CanNotDelete

Error message

SR.CanNotDelete

What it means

StorageInfo.DeleteSubStorage catches a COMException from IStorage::DestroyElement whose error code is not STG_E_ACCESSDENIED and throws IOException with SR.CanNotDelete. It is the generic 'we could not delete this sub-storage' path for any COM failure other than access denied (e.g. element busy, name invalid, file corruption).

Solutions

  1. Inspect the inner COMException's HResult to identify the underlying STG_E_* code.
  2. Close all StreamInfo/StorageInfo objects and enumerators derived from the container before deleting.
  3. Verify the file is not corrupt by opening it in the owning application or repairing it.
  4. Retry on a writable copy of the file if the original medium is suspect.

Example fix

// before
storageInfo.DeleteSubStorage(name); // throws IOException
// after
try { storageInfo.DeleteSubStorage(name); }
catch (IOException e) when (e.InnerException is COMException ce) {
    // inspect ce.HResult (STG_E_* code) and handle/retry
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!File.Exists(path)) throw new FileNotFoundException(path);
if (new FileInfo(path).Length == 0) throw new InvalidDataException("Empty compound file");

Prevention

When it happens

Trigger: Calling DeleteSubStorage/Delete on a storage whose IStorage::DestroyElement fails with any HRESULT other than STG_E_ACCESSDENIED — corrupt compound file, storage opened in a sharing-incompatible mode, or a name that does not resolve.

Common situations: Deleting entries in a truncated or partially-written compound document; deleting a sub-storage while enumerators/streams are still bound to it in conflicting modes; media or file-system I/O errors.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

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

            }
        }
        
        // Make the call to the underlying OLE mechanism to remove the element.            
        try
        {
            core.safeIStorage.DestroyElement( elementNameInternal );
        }
        catch( COMException e )
        {
            if( e.ErrorCode == SafeNativeCompoundFileConstants.STG_E_ACCESSDENIED )
            {
                throw new UnauthorizedAccessException(
                    SR.CanNotDeleteAccessDenied,
                    e );
            }
            else
            {
                throw new IOException(
                    SR.CanNotDelete,
                    e );
            }
        }

        // Invalidate enumerators
        InvalidateEnumerators();

            // Remove the now-meaningless name, which also signifies disposed status.
            if (deadElementWalking is StorageInfoCore deadStorageInfoCore)
            {

                // Erase this storage's existence
                deadStorageInfoCore.storageName = null;
                if (null != deadStorageInfoCore.safeIStorage)
                {
                    ((IDisposable)deadStorageInfoCore.safeIStorage).Dispose();
                    deadStorageInfoCore.safeIStorage = null;

View on GitHub (pinned to 81131a70a4)