{"record":{"id":"2e4c13845cedc8f5","repo":"dotnet/wpf","slug":"sr-storagerootdisposed","errorCode":null,"errorMessage":"SR.StorageRootDisposed","messagePattern":"SR\\.StorageRootDisposed","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageRoot.cs","lineNumber":443,"sourceCode":"            dataSpaceManager = new DataSpaceManager( this );\n            dataSpaceManagerInitializationInProgress = false;\n        }\n\n        return dataSpaceManager;\n    }\n\n    internal IStorage GetRootIStorage()\n    {\n        return rootIStorage;\n    }\n\n    // Check whether this StorageRoot class still has its underlying storage.\n    //  If not, throw an object disposed exception.  This should be checked from\n    //  every non-static container external API.\n    internal void CheckRootDisposedStatus()\n    {\n        if( RootDisposed )\n            throw new ObjectDisposedException(null, SR.StorageRootDisposed);\n    }\n\n    // Check whether this StorageRoot class still has its underlying storage.\n    internal bool RootDisposed\n    {\n        get\n        {\n            return ( null == rootIStorage );\n        }\n    }\n\n    /// <summary>\n    /// This will create a container StorageRoot based on the given IStorage\n    /// interface\n    /// </summary>\n    /// <param name=\"root\">The new IStorage (RCW) upon which to build the new StorageRoot</param>\n    /// <returns>New StorageRoot object built on the given IStorage</returns>\n    private static StorageRoot CreateOnIStorage( IStorage root )","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/CompoundFile/StorageRoot.cs#L425-L461","documentation":"This is an ObjectDisposedException thrown by StorageRoot.CheckRootDisposedStatus when the compound file's root storage has already been disposed (RootDisposed is true). The CompoundFile-based Packaging APIs (StorageRoot, StorageInfo, StreamInfo) invalidate the underlying OLE structured storage when the root is closed/disposed, and every non-static external API re-checks disposal before acting. It signals the developer called a packaging API after the owning CompoundFile/StorageRoot was closed.","triggerScenarios":"Calling OpenAccess, Flush, or GetDataSpaceManager on a StorageRoot (or any StorageInfo/StreamInfo operation that routes through these) after the root compound file has been disposed/closed, e.g. using a Package or StreamInfo obtained before a 'using' block ended.","commonSituations":"Using a Package/StorageRoot inside a 'using' or after Close()/Dispose(); caching a StreamInfo/StreamInfo-derived object in a field and using it after the file was closed; closing the package in one method and writing in another.","solutions":["Ensure all reads/writes complete before disposing the CompoundFile/Package; keep the owning object alive for the duration of use.","Re-open the compound file (e.g. StorageRoot.Open / Package.Open) if you need access after disposal instead of reusing the old instance.","Check RootDisposed (or guard with try/catch ObjectDisposedException) before calling APIs on long-lived references.","Fix lifetime ownership: don't dispose in one layer while another layer still holds references."],"exampleFix":"// before\nvar root = StorageRoot.Open(path); // disposed elsewhere/earlier\nroot.Flush(); // throws ObjectDisposedException\n// after\nusing (var root = StorageRoot.Open(path))\n{\n    // do all work here, before disposal\n    root.Flush();\n}","handlingStrategy":"try-catch","validationCode":"if (root == null || root.RootDisposed) throw new InvalidOperationException(\"Compound file root already disposed.\");","typeGuard":"bool IsUsable(StorageRoot root) => root != null && !root.RootDisposed;","tryCatchPattern":"try { root.Flush(); }\ncatch (ObjectDisposedException) { /* reopen the compound file and retry the operation */ }","preventionTips":["Scope the StorageRoot/Package in a using block and do all work inside it.","Never cache StreamInfo/StorageInfo references beyond the owning file's lifetime.","Check RootDisposed before API calls on long-lived references.","Centralize open/close so disposal happens exactly once, after all consumers finish."],"tags":["object-disposed","lifecycle","wpf","packaging","compound-file"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}