dotnet/wpf · error · ObjectDisposedException

Cannot access Stream object because it was closed or…

Error message

Cannot access Stream object because it was closed or disposed.

What it means

UnsafeLockBytesOnStream implements CheckDisposed, called by every ILockBytes operation (ReadAt, WriteAt, Flush, SetSize, Stat). After Dispose has been called, _baseStream is set to null, and any subsequent operation throws ObjectDisposedException with the 'Cannot access Stream object because it was closed or disposed' message.

Solutions

  1. Ensure the underlying stream lives as long as all uses of the compound file; only dispose once, after all operations complete.
  2. Guard accesses with a disposed check, or catch ObjectDisposedException where post-dispose calls are benign.
  3. Restructure so callbacks/async work complete before disposing the owning Package.

Example fix

// before
package.Close();
var stat = lockBytes.Stat(0); // throws
// after
var stat = lockBytes.Stat(0);
package.Close();
Defensive patterns

Strategy: try-catch

Validate before calling

bool usable = lockBytes != null && !isDisposed; // track your own disposed flag

Type guard

bool IsAlive(UnsafeLockBytesOnStream lb) => lb != null && !lb.Disposed;

Try / catch

try { lockBytes.Stat(grfStatFlag); }
catch (ObjectDisposedException) { /* stream was closed; reopen or abort */ }

Prevention

When it happens

Trigger: Calling any ILockBytes/IStream operation after UnsafeLockBytesOnStream.Dispose() — e.g. using the compound file object after its owning Package/stream was closed, or a callback firing after disposal.

Common situations: Double-closing a Package (using-block plus explicit Dispose), holding a reference to a compound-file stream after the parent package is closed, or async operations outliving the stream's lifetime.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/e361beb0b4196a1e. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/PrivateUnsafeNativeCompoundFileMethods.cs:105

            /// <param name="disposing"></param>
            protected virtual void Dispose(bool disposing)
            {
                if (disposing && (_baseStream != null))
                {
                    // We only set the _baseStream to null without closing it,
                    // because _baseStream is a reference of an outside stream,
                    // and was set when this class was constructed. We didn't open 
                    // the stream and should leave the original owner of the stream
                    // to close it.
                    _baseStream = null;
                }
            }

            private void CheckDisposed()
            {
                if (_baseStream==null)
                {
                    throw new ObjectDisposedException(null, SR.StreamObjectDisposed);
                }
            }

            void UnsafeNativeILockBytes.ReadAt (
                UInt64 offset,
                [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] Byte[] pv,
                int cb,
                out int pcbRead)
            {
                CheckDisposed();
                checked { _baseStream.Seek( (long)offset, SeekOrigin.Begin ); }
                pcbRead = _baseStream.Read( pv, 0, cb );
            }

            void UnsafeNativeILockBytes.WriteAt(
                UInt64 offset,
                [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] Byte[] pv,
                int cb,

View on GitHub (pinned to 81131a70a4)