dotnet/wpf · error · ObjectDisposedException

SR.StreamObjectDisposed

Error message

SR.StreamObjectDisposed

What it means

ObjectDisposedException (message SR.StreamObjectDisposed) thrown by VersionedStream.CheckDisposed when a public Stream API (Length, Position, Flush, Seek, SetLength, Read) is used after the underlying stream was closed (its _stream field set to null). It is the standard 'use after close' guard for versioned compound-file streams.

Solutions

  1. Read all needed data before the owning package/CompoundFile is disposed
  2. Reopen the compound file/package to obtain a fresh stream instead of reusing the closed one
  3. Restructure code so stream lifetime matches usage scope (keep the owning object alive while the stream is referenced)
  4. Guard accesses with an IsDisposed/can-read check when the stream may already be closed

Example fix

// before: using a stream after the package was disposed
Package package;
using (package = Package.Open(path))
{
    partStream = part.GetStream();
}
long len = partStream.Length; // ObjectDisposedException
// after: consume the stream inside the owning package's lifetime
using (var package = Package.Open(path))
{
    using (var partStream = part.GetStream())
    {
        long len = partStream.Length; // OK
        ProcessStream(partStream);
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

static bool IsUsable(Stream s) => s != null && s.CanRead && s.CanSeek; // CanRead/CanSeek are false after disposal on most streams

Type guard

bool IsAliveStream(VersionedStream vs) => vs != null && vs.CanRead;

Try / catch

try
{
    long len = versionedStream.Length;
}
catch (ObjectDisposedException)
{
    // reopen the owning package/stream and retry once
    using (var fresh = ReopenStream())
    {
        len = fresh.Length;
    }
}

Prevention

When it happens

Trigger: Calling any read/seek/flush member of a VersionedStream after Close()/Dispose() was called on it — e.g. keeping a reference to the stream after the CompoundFile/package was disposed, or finishing a using block and then reading Position.

Common situations: Disposing a package in a using block but retaining stream references in fields or closures; deferred/lazy reads (e.g. in async code or event handlers) that run after disposal; double-dispose followed by an accidental access.

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

Appendix: source

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

                {
                    _stream.Close();
                }
            }
            finally
            {
                _stream = null;
                base.Dispose(disposing);
            }
        }

        /// <summary>
        /// Call this before accepting any public API call (except some Stream calls that
        /// are allowed to respond even when Closed
        /// </summary>
        protected void CheckDisposed()
        {
            if (_stream == null)
                throw new ObjectDisposedException(null, SR.StreamObjectDisposed);
        }

        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
        private VersionedStreamOwner    _versionOwner;
        private Stream                  _stream;            // null indicates Disposed state
    }
}

View on GitHub (pinned to 81131a70a4)