dotnet/wpf · error · ObjectDisposedException
SR.StreamObjectDisposed
Error message
SR.StreamObjectDisposed
What it means
RightsManagementEncryptedStream.CheckDisposed throws ObjectDisposedException(SR.StreamObjectDisposed) when any stream operation (Length, Position, Flush, Seek, SetLength, Read, Write, Close paths) is attempted after the stream has been closed/disposed (_baseStream == null). The class nulls its base stream on Close, so any subsequent member access is rejected.
Solutions
- Do not use the stream after Dispose/Close; scope all access inside a single using block.
- Check ObjectDisposedException (or wrap access) and reopen the package/stream if you need to read again.
- Audit lifetime ownership: ensure the owner (Package/EncryptedPackageEnvelope) outlives every consumer of the stream.
- If you must detect disposal, test stream.CanRead/CanSeek before use (returns false after dispose) rather than calling members that throw.
- Fix double-dispose patterns: remove redundant explicit Close when the stream is in a using statement.
Example fix
// before: stream used after disposal
RightsManagementEncryptedStream stream;
using (stream = CreateRmStream())
{
stream.Read(buf, 0, buf.Length);
}
stream.Seek(0, SeekOrigin.Begin); // ObjectDisposedException
// after: all work inside the using scope
using var stream = CreateRmStream();
stream.Read(buf, 0, buf.Length);
stream.Seek(0, SeekOrigin.Begin); Defensive patterns
Strategy: type-guard
Validate before calling
// guard every access
if (stream == null || !stream.CanRead)
throw new InvalidOperationException("The rights-managed stream is closed; reopen the package first."); Type guard
static bool IsOpen(Stream s) => s != null && s.CanRead && s.CanSeek; // false after Dispose/Close
Try / catch
try
{
stream.Seek(0, SeekOrigin.Begin);
}
catch (ObjectDisposedException)
{
// stream was closed; reopen owning package and retry once
stream = ReopenRmStream();
} Prevention
- Scope stream usage inside using blocks; never keep references past disposal.
- Ensure the owning Package/EncryptedPackageEnvelope outlives the stream consumer.
- Avoid using disposed streams from other threads; synchronize package lifetime.
- Remove redundant explicit Close() calls when Dispose is already managed by using.
When it happens
Trigger: Calling Read/Seek/Length/Position/Flush/SetLength/Write on a RightsManagementEncryptedStream after Close() or Dispose() has been called — e.g. using the stream after a using block ends, or a cached stream reference used post-disposal.
Common situations: Holding a long-lived reference to the encrypted stream while the XpsDocument/Package that owns it was closed; double-dispose via nested using blocks; reading the stream on another thread after the package was disposed; reusing a stream variable after an earlier operation closed it.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- EncryptedPackageEnvelope object was disposed.
- SR.StorageBasedPackagePropertiesDiposed
- SR.StreamObjectDisposed
- Cannot access Stream object because it was closed or…
- SR.ByteRangeDownloaderDisposed
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/78647fe16e8752bd.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptedStream.cs:717
{
long firstBlockNumber = GetBlockNo(blockSize, start);
firstBlockOffset = firstBlockNumber * blockSize;
blockCount = GetBlockSpanCount(blockSize, start, size);
if (canMergeBlocks)
{
// we need to recalculate everything as if it were a single large block
blockSize = (int)(blockSize * blockCount);
blockCount = 1;
}
}
}
private void CheckDisposed()
{
if (_baseStream == null)
{
throw new ObjectDisposedException(null, SR.StreamObjectDisposed);
}
}
private void FlushCacheIfNecessary()
{
checked
{
if (_readCache.MemoryConsumption + _writeCache.MemoryConsumption > _autoFlushHighWaterMark)
{
FlushCache();
}
}
}
private void FlushCache()
{
checked
{View on GitHub (pinned to 81131a70a4)