{"record":{"id":"24fc65634071d63c","repo":"dotnet/wpf","slug":"current-stream-object-was-closed-and-disposed-cannot-access-24fc65","errorCode":null,"errorMessage":"Current stream object was closed and disposed. Cannot access a closed stream.","messagePattern":"Current stream object was closed and disposed\\. Cannot access a closed stream\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/IO/Packaging/ManagedIStream.cs","lineNumber":136,"sourceCode":"            };\n            if (_ioStream.CanRead && _ioStream.CanWrite)\n            {\n                streamStats.grfMode |= NativeMethods.STGM_READWRITE;\n            }\n            else if (_ioStream.CanRead)\n            {\n                streamStats.grfMode |= NativeMethods.STGM_READ;\n            }\n            else if (_ioStream.CanWrite)\n            {\n                streamStats.grfMode |= NativeMethods.STGM_WRITE;\n            }\n            else\n            {\n                // A stream that is neither readable nor writable is a closed stream.\n                // Note the use of an exception that is known to the interop marshaller\n                // (unlike ObjectDisposedException).\n                throw new IOException(SR.StreamObjectDisposed);\n            }\n        }\n\n        /// <summary>\n        /// Write at most bufferSize bytes from buffer.\n        /// </summary>\n        void IStream.Write(Byte[] buffer, Int32 bufferSize, IntPtr bytesWrittenPtr)\n        {\n            _ioStream.Write(buffer, 0, bufferSize);\n            if (bytesWrittenPtr != IntPtr.Zero)\n            {\n                // If fewer than bufferSize bytes had been written, an exception would\n                // have been thrown, so it can be assumed we wrote bufferSize bytes.\n                Marshal.WriteInt32(bytesWrittenPtr, bufferSize);\n            }\n        }\n\n        #region Unimplemented methods","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/IO/Packaging/ManagedIStream.cs#L118-L154","documentation":"ManagedIStream.Stat reports stream attributes by probing CanRead/CanWrite. A stream that is neither readable nor writable is treated as closed, so it throws IOException with the StreamObjectDisposed message — deliberately IOException (not ObjectDisposedException) because the interop marshaller does not map ObjectDisposedException back to COM HRESULTs correctly.","triggerScenarios":"Calling IStream.Stat (or ManagedIStream.Stat directly) on a Stream that has been closed/disposed, so both CanRead and CanWrite are false.","commonSituations":"COM clients holding an IStream reference after the managed stream was disposed; disposing a Package/FileStream while unmanaged code still holds the IStream wrapper; finalizer ordering closing the stream before Stat is called.","solutions":["Keep the underlying managed stream open for as long as the IStream wrapper is used by native code.","Check stream.CanRead || stream.CanWrite before calling Stat and reopen/re-create the stream if false.","Catch IOException and treat it as a disposed stream: re-open the source and rebuild the ManagedIStream."],"exampleFix":"// before\npIStream.Stat(out stat, 0); // stream already closed\n// after\nif (stream.CanRead || stream.CanWrite)\n    pIStream.Stat(out stat, 0);\nelse\n    stream = File.OpenRead(path); // re-open before retrying","handlingStrategy":"try-catch","validationCode":"bool streamAlive = stream != null && (stream.CanRead || stream.CanWrite);","typeGuard":"static bool IsOpen(Stream s) => s != null && (s.CanRead || s.CanWrite);","tryCatchPattern":"try { pIStream.Stat(out stat, 0); } catch (IOException) when (!stream.CanRead && !stream.CanWrite) { /* stream disposed: re-open and rebuild IStream */ }","preventionTips":["Keep the managed stream alive while native code holds the IStream wrapper","Use GC.KeepAlive or extend using-scope across all interop calls","Check CanRead/CanWrite before Stat and other IStream members"],"tags":["io","istream","stream-disposed","interop"],"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-21T21:30:21.729Z"}