{"record":{"id":"cbfff4bee2a2b876","repo":"dotnet/wpf","slug":"sr-cannotdeleteinreadonly","errorCode":null,"errorMessage":"SR.CanNotDeleteInReadOnly","messagePattern":"SR\\.CanNotDeleteInReadOnly","errorType":"exception","errorClass":"UnauthorizedAccessException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageInfo.cs","lineNumber":755,"sourceCode":"\n    /// <summary>\n    /// Destroys an element and removes the references ued internally.\n    /// </summary>\n    internal void DestroyElement( string elementNameInternal )\n    {\n        object deadElementWalking = core.elementInfoCores[ elementNameInternal ];\n        // It's an internal error if we try to call this without first\n        //  verifying that it is indeed there.\n        Debug.Assert( null != deadElementWalking,\n            \"Caller should have already verified that there's something to delete.\");\n\n        // Can't delete if we're in read-only mode.  This catches some but not\n        //  all invalid delete scenarios - anything else would come back as a\n        //  COMException of some kind that will be caught and wrapped in an\n        //  IOException in the try/catch below.\n        if( FileAccess.Read == Root.OpenAccess )\n        {\n            throw new UnauthorizedAccessException(\n                SR.CanNotDeleteInReadOnly);\n        }\n\n        //Clean out the entry in dataspacemanager for stream transforms\n        DataSpaceManager manager = Root.GetDataSpaceManager();\n        if( null != manager )\n        {\n             if( deadElementWalking is StorageInfoCore )\n            {\n                //if the element getting deleted is a storage, make sure to delete all its children's references.\n                string name = ((StorageInfoCore)deadElementWalking).storageName;\n                StorageInfo stInfo = new StorageInfo(this, name);\n                RemoveSubStorageEntryFromDataSpaceMap(stInfo);\n            }\n            else if( deadElementWalking is StreamInfoCore )\n            {\n                //if the element getting deleted is a stream, the container reference should be removed from dataspacemap of dataspace manager.\n                manager.RemoveContainerFromDataSpaceMap(new CompoundFileStreamReference( FullNameInternal, elementNameInternal ));","sourceCodeStart":737,"sourceCodeEnd":773,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageInfo.cs#L737-L773","documentation":"Thrown by StorageInfo.DestroyElement (used by DeleteSubStorage/DeleteStream paths) when the root compound file was opened with FileAccess.Read. Deletion mutates the file, so the library fails fast with UnauthorizedAccessException; other invalid delete scenarios surface later as wrapped COMExceptions.","triggerScenarios":"Calling DestroyElement, DeleteSubStorage or Delete (via transform cleanup in WriteTransformDefinitions) on any StorageInfo belonging to a root opened with FileAccess.Read.","commonSituations":"Reading an XPS/RM package opened from a read-only stream or URI but then running cleanup/rewrite logic on it; tools that open packages read-only for inspection yet try to prune old fragment storages.","solutions":["Reopen the root with FileAccess.ReadWrite before performing deletions","Skip deletion logic when Root.OpenAccess == FileAccess.Read (inspect-before-mutate guard)","Copy the file to a writable location and open the copy read-write if the original must remain untouched","Separate read/inspection code paths from mutation code paths so read-only roots never reach DestroyElement"],"exampleFix":"// before\nvar root = StorageRoot.OpenOnFile(path, FileMode.Open, FileAccess.Read);\nroot.DeleteSubStorage(\"oldFragments\");\n// after\nvar root = StorageRoot.OpenOnFile(path, FileMode.Open, FileAccess.ReadWrite);\nroot.DeleteSubStorage(\"oldFragments\");","handlingStrategy":"validation","validationCode":"if (root.OpenAccess == FileAccess.Read)\n    throw new InvalidOperationException(\"Deletion requires a read-write root\");","typeGuard":null,"tryCatchPattern":"try { root.DeleteSubStorage(name); }\ncatch (UnauthorizedAccessException ex) { /* root opened read-only: reopen ReadWrite or skip cleanup */ }","preventionTips":["Check Root.OpenAccess before any mutation call","Keep inspection and mutation on separate roots","Reopen with FileAccess.ReadWrite for any destructive operation"],"tags":["compound-file","read-only","delete","permissions"],"backgroundTag":"permission-denied","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}