dotnet/wpf · error · UnauthorizedAccessException
SR.CanNotDeleteInReadOnly
Error message
SR.CanNotDeleteInReadOnly
What it means
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.
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
Example fix
// before
var root = StorageRoot.OpenOnFile(path, FileMode.Open, FileAccess.Read);
root.DeleteSubStorage("oldFragments");
// after
var root = StorageRoot.OpenOnFile(path, FileMode.Open, FileAccess.ReadWrite);
root.DeleteSubStorage("oldFragments"); Defensive patterns
Strategy: validation
Validate before calling
if (root.OpenAccess == FileAccess.Read)
throw new InvalidOperationException("Deletion requires a read-write root"); Try / catch
try { root.DeleteSubStorage(name); }
catch (UnauthorizedAccessException ex) { /* root opened read-only: reopen ReadWrite or skip cleanup */ } Prevention
- Check Root.OpenAccess before any mutation call
- Keep inspection and mutation on separate roots
- Reopen with FileAccess.ReadWrite for any destructive operation
When it happens
Trigger: Calling DestroyElement, DeleteSubStorage or Delete (via transform cleanup in WriteTransformDefinitions) on any StorageInfo belonging to a root opened with FileAccess.Read.
Common situations: 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.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- SR.CanNotCreateContainerOnReadOnlyStream
- SR.CanNotDeleteNonEmptyStorage
- STG_E_ACCESSDENIED
- ' ' name is already in use.
- 0x80040209
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/cbfff4bee2a2b876.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageInfo.cs:755
/// <summary>
/// Destroys an element and removes the references ued internally.
/// </summary>
internal void DestroyElement( string elementNameInternal )
{
object deadElementWalking = core.elementInfoCores[ elementNameInternal ];
// It's an internal error if we try to call this without first
// verifying that it is indeed there.
Debug.Assert( null != deadElementWalking,
"Caller should have already verified that there's something to delete.");
// Can't delete if we're in read-only mode. This catches some but not
// all invalid delete scenarios - anything else would come back as a
// COMException of some kind that will be caught and wrapped in an
// IOException in the try/catch below.
if( FileAccess.Read == Root.OpenAccess )
{
throw new UnauthorizedAccessException(
SR.CanNotDeleteInReadOnly);
}
//Clean out the entry in dataspacemanager for stream transforms
DataSpaceManager manager = Root.GetDataSpaceManager();
if( null != manager )
{
if( deadElementWalking is StorageInfoCore )
{
//if the element getting deleted is a storage, make sure to delete all its children's references.
string name = ((StorageInfoCore)deadElementWalking).storageName;
StorageInfo stInfo = new StorageInfo(this, name);
RemoveSubStorageEntryFromDataSpaceMap(stInfo);
}
else if( deadElementWalking is StreamInfoCore )
{
//if the element getting deleted is a stream, the container reference should be removed from dataspacemap of dataspace manager.
manager.RemoveContainerFromDataSpaceMap(new CompoundFileStreamReference( FullNameInternal, elementNameInternal ));View on GitHub (pinned to 81131a70a4)