{"record":{"id":"698d93c4dca28ac5","repo":"SixLabors/ImageSharp","slug":"the-stream-is-closed","errorCode":null,"errorMessage":"The stream is closed.","messagePattern":"The stream is closed\\.","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/ImageSharp/IO/ChunkedMemoryStream.cs","lineNumber":386,"sourceCode":"        }\n\n        this.bufferIndex = currentChunkIndex;\n\n        // Safe to cast here as we know the offset is less than the chunk length.\n        this.chunkIndex = (int)offset;\n    }\n\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    private void EnsureNotDisposed()\n    {\n        if (this.isDisposed)\n        {\n            ThrowDisposed();\n        }\n    }\n\n    [MethodImpl(MethodImplOptions.NoInlining)]\n    private static void ThrowDisposed() => throw new ObjectDisposedException(nameof(ChunkedMemoryStream), \"The stream is closed.\");\n\n    private sealed class MemoryChunkBuffer : IDisposable\n    {\n        private readonly List<MemoryChunk> memoryChunks = [];\n        private readonly MemoryAllocator allocator;\n        private readonly int allocatorCapacity;\n        private bool isDisposed;\n\n        public MemoryChunkBuffer(MemoryAllocator allocator)\n        {\n            this.allocatorCapacity = allocator.GetBufferCapacityInBytes();\n            this.allocator = allocator;\n        }\n\n        public int ChunkCount => this.memoryChunks.Count;\n\n        public long Length { get; private set; }\n","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/SixLabors/ImageSharp/blob/59ce6af6fc29027cda277ef62d4d1694a8acce91/src/ImageSharp/IO/ChunkedMemoryStream.cs#L368-L404","documentation":"ChunkedMemoryStream.ThrowDisposed throws ObjectDisposedException when a method is used after the stream was disposed; EnsureNotDisposed is called on member access. ChunkedMemoryStream is ImageSharp's internal pooled memory stream, so accessing it after Dispose is a use-after-dispose bug in the caller.","triggerScenarios":"Calling Read/Write/Seek/Length/Position on a ChunkedMemoryStream after Dispose() or a 'using' block ended; returning the stream from a method whose using scope already closed it; sharing the stream across threads where one disposes it early.","commonSituations":"Encoding/decoding callbacks that capture the stream and run after the owning scope disposes it; async code with a 'using' that doesn't await before disposal; caching the stream for later reuse.","solutions":["Ensure all reads/writes complete before Dispose — await async work inside the using block.","Lengthen the stream's lifetime (return the buffer contents via ToArray/GetBuffer instead of the stream).","Check CanRead before use and treat false as disposed; guard with ObjectDisposedException handling.","If ownership is pooled/internal, let ImageSharp manage the stream and copy the data out at the documented point."],"exampleFix":"// before\nChunkedMemoryStream ms = CreateStream();\nms.Dispose();\nvar len = ms.Length; // ObjectDisposedException\n// after\nusing var ms = CreateStream();\nvar len = ms.Length;\nbyte[] data = ms.ToArray(); // copy out before dispose","handlingStrategy":"validation","validationCode":"if (stream is ChunkedMemoryStream cms && !cms.CanRead) throw new InvalidOperationException(\"Stream already disposed\");","typeGuard":"static bool IsUsable(Stream s) => s is { CanRead: true, CanWrite: false } or { CanRead: true, CanWrite: true };","tryCatchPattern":"try { buffer = stream.GetSpan().ToArray(); }\ncatch (ObjectDisposedException ex) { log.Error(ex, \"ChunkedMemoryStream used after dispose\"); throw; }","preventionTips":["Keep 'using' scopes alive across all async operations (await inside using)","Copy data out (ToArray) before the owning scope disposes","Never share a disposable stream across threads without lifetime ownership"],"tags":["stream","disposed","lifetime","memory"],"backgroundTag":"invalid-state-transition","analyzedSha":"59ce6af6fc29027cda277ef62d4d1694a8acce91","analyzedAt":"2026-09-13T18:34:59.331Z","contentChangedAt":"2026-09-13T18:34:59.331Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}