dotnet/wpf · error · IOException
SR.CanNotOpenStorage
Error message
SR.CanNotOpenStorage
What it means
StorageInfo.CanOpenStorage calls IStorage::OpenStorage; when the returned native error code is anything other than STG_E_FILENOTFOUND the library throws IOException with SR.CanNotOpenStorage, wrapping a COMException named for IStorage::OpenStorage. STG_E_FILENOTFOUND is deliberately not thrown — instead openSuccess stays false so callers can check existence.
Solutions
- Check the exact child storage name (StgOpenStorage names are exact, not case-insensitive in all paths).
- Reopen the StorageRoot with the correct FileAccess for the intended operation.
- Verify the compound file is not corrupt by opening it in its owning application.
- Catch IOException and inspect the inner COMException HResult for the specific STG_E_* code.
Example fix
// before
var child = root.GetStorageInfo("Data"); // may throw IOException
// after
StreamInfo si;
if (root.TryGetStorageInfo("Data", out var st) || root.StorageInfos.Any(s => s.Name == "Data"))
child = root.GetStorageInfo("Data"); Defensive patterns
Strategy: validation
Validate before calling
bool exists = root.GetStorageInfos().Any(s => s.Name == childName); if (!exists) return null; // avoid OpenStorage on a bogus name
Prevention
- Verify child names exactly before opening.
- Match FileAccess of the child operation to how the root was opened.
- Catch IOException and inspect the inner COMException HResult.
When it happens
Trigger: Opening a named sub-storage whose IStorage::OpenStorage call fails with an error other than STG_E_FILENOTFOUND (access denied, name invalid, storage disposed) via GetStorageInfo/child storage access.
Common situations: Case/name mismatch resolving to invalid name errors, compound file corruption, accessing a storage on a root opened read-only when write-type access is requested.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- SR.CanNotDelete
- Read
- SR.CanNotCreateContainerOnReadOnlyStream
- SR.CanNotCreateStorageRootOnNonReadableStream
- SR.CanNotOnNonExistStorage
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/b9aeedfdc454d708.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageInfo.cs:1093
int nativeCallErrorCode = 0;
nativeCallErrorCode = core.safeIStorage.OpenStorage(
nameInternal,
null,
(GetStat().grfMode & SafeNativeCompoundFileConstants.STGM_READWRITE_Bits)
| SafeNativeCompoundFileConstants.STGM_SHARE_EXCLUSIVE,
IntPtr.Zero,
0,
out childCore.safeIStorage );
if( SafeNativeCompoundFileConstants.S_OK == nativeCallErrorCode )
{
openSuccess = true;
}
else if( SafeNativeCompoundFileConstants.STG_E_FILENOTFOUND != nativeCallErrorCode )
{
// Error is not STG_E_FILENOTFOUND, pass it on.
throw new IOException(
SR.CanNotOpenStorage,
new COMException(
SR.Format(SR.NamedAPIFailure, "IStorage::OpenStorage"),
nativeCallErrorCode ));
}
// STG_E_NOTFOUND - return openSuccess as false
return openSuccess;
}
/// <summary>
/// Most of the time internal methods that want to do an internal check
/// to see if a storage exists is only interested in proceeding if it does.
/// If it doesn't, abort with an exception. This implements the little
/// shortcut.
/// </summary>
private void VerifyExists()
{View on GitHub (pinned to 81131a70a4)