dotnet/wpf · error · ObjectDisposedException

SR.StreamObjectDisposed

Error message

SR.StreamObjectDisposed

What it means

CFStream.CheckDisposedStatus throws ObjectDisposedException with SR.StreamObjectDisposed when any member (Length, Position, Flush, Seek, SetLength, Read, Write) is used after the CFStream has been disposed. Compound-file streams wrap native IStream handles that are released on Dispose, so further use is impossible. This is standard Stream disposed-state enforcement.

Solutions

  1. Keep all stream usage inside the using/scope where the stream is alive
  2. Check the parent CompoundFile/Package lifetime — disposing it disposes child streams
  3. Track disposal with stream.CanRead (false after dispose) or a null-check after ownership transfer
  4. Restructure so async work completes before disposing the owning file
  5. Catch ObjectDisposedException as a last-resort guard in event handlers

Example fix

// before
Stream s;
using (var cf = new CompoundFile(path)) {
    s = cf.OpenStream(name);
}
s.Read(buf, 0, buf.Length); // throws
// after
using (var cf = new CompoundFile(path)) {
    using (var s = cf.OpenStream(name)) {
        s.Read(buf, 0, buf.Length);
    }
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (stream == null || !stream.CanRead) throw new ObjectDisposedException(nameof(stream));

Type guard

static bool IsUsable(Stream s) => s != null && s.CanRead;

Try / catch

try { stream.Read(buffer, 0, count); } catch (ObjectDisposedException) { /* reopen the stream */ }

Prevention

When it happens

Trigger: Calling Read/Seek/Length/Position/Flush/SetLength/Write after calling Dispose() or after the containing CompoundFile was closed/disposed; using a stream captured in a lambda or event handler that fires after disposal.

Common situations: Using-block scope bugs where a stream reference escapes the using block; closing the parent Package/compound file while child streams are still referenced; async continuations running after the stream was disposed.

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/d2e76dfcdf31bedb. Report an issue: GitHub.

Appendix: source

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

        }

        if( count != written )
            throw new IOException(
                SR.WriteFailure);
}

    //------------------------------------------------------
    //
    //  Internal Methods
    //
    //------------------------------------------------------

    // Check whether this Stream object is still valid.  If not, thrown an
    //  ObjectDisposedException.
    internal void CheckDisposedStatus()
    {
        if( StreamDisposed )
            throw new ObjectDisposedException(null, SR.StreamObjectDisposed);
    }

    // Check whether this Stream object is still valid.
    internal bool StreamDisposed
    {
        get
        {
            return (backReference.StreamInfoDisposed || ( null == _safeIStream ));
        }
    }

    // Constructors
    internal CFStream(
        IStream underlyingStream,
        FileAccess openAccess,
        StreamInfo creator)
    {
        _safeIStream = underlyingStream;

View on GitHub (pinned to 81131a70a4)