{"record":{"id":"78647fe16e8752bd","repo":"dotnet/wpf","slug":"sr-streamobjectdisposed-rightsmanagementencryptedstream","errorCode":null,"errorMessage":"SR.StreamObjectDisposed","messagePattern":"SR\\.StreamObjectDisposed","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptedStream.cs","lineNumber":717,"sourceCode":"            {\n                long firstBlockNumber = GetBlockNo(blockSize, start);\n                firstBlockOffset = firstBlockNumber * blockSize;\n                blockCount = GetBlockSpanCount(blockSize, start, size);\n\n                if (canMergeBlocks)\n                {\n                    // we need to recalculate everything as if it were a single large block \n                    blockSize = (int)(blockSize * blockCount);\n                    blockCount = 1;\n                }\n            }\n        }\n\n        private void CheckDisposed()\n        {\n            if (_baseStream == null)\n            {\n                throw new ObjectDisposedException(null, SR.StreamObjectDisposed);\n            }\n        }\n\n        private void FlushCacheIfNecessary()\n        {\n            checked\n            {\n                if (_readCache.MemoryConsumption + _writeCache.MemoryConsumption > _autoFlushHighWaterMark)\n                {\n                    FlushCache();\n                }                \n            }\n}\n        \n        private void FlushCache()\n        {\n            checked\n            {","sourceCodeStart":699,"sourceCodeEnd":735,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/RightsManagementEncryptedStream.cs#L699-L735","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: stream used after disposal\nRightsManagementEncryptedStream stream;\nusing (stream = CreateRmStream())\n{\n    stream.Read(buf, 0, buf.Length);\n}\nstream.Seek(0, SeekOrigin.Begin); // ObjectDisposedException\n\n// after: all work inside the using scope\nusing var stream = CreateRmStream();\nstream.Read(buf, 0, buf.Length);\nstream.Seek(0, SeekOrigin.Begin);","handlingStrategy":"type-guard","validationCode":"// guard every access\nif (stream == null || !stream.CanRead)\n    throw new InvalidOperationException(\"The rights-managed stream is closed; reopen the package first.\");","typeGuard":"static bool IsOpen(Stream s) => s != null && s.CanRead && s.CanSeek; // false after Dispose/Close","tryCatchPattern":"try\n{\n    stream.Seek(0, SeekOrigin.Begin);\n}\ncatch (ObjectDisposedException)\n{\n    // stream was closed; reopen owning package and retry once\n    stream = ReopenRmStream();\n}","preventionTips":["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."],"tags":["wpf","packaging","stream","object-disposed","lifetime"],"backgroundTag":"unsupported-operation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}