{"record":{"id":"6938d08c337afa9e","repo":"microsoft/garnet","slug":"read-is-not-supported-for-diskstreamwritebuffer","errorCode":null,"errorMessage":"Read is not supported for DiskStreamWriteBuffer","messagePattern":"Read is not supported for DiskStreamWriteBuffer","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"libs/storage/Tsavorite/cs/src/core/Allocator/ObjectSerialization/ObjectLogWriter.cs","lineNumber":333,"sourceCode":"            // If we haven't yet instantiated the serializer do so now.\n            if (valueObjectSerializer is null)\n            {\n                pinnedMemoryStream = new(this);\n                valueObjectSerializer = storeFunctions.CreateValueObjectSerializer();\n                valueObjectSerializer.BeginSerialize(pinnedMemoryStream);\n            }\n\n            valueObjectSerializer.Serialize(valueObject);\n            OnSerializeComplete(valueObject);\n        }\n\n        void OnSerializeComplete(IHeapObject valueObject)\n        {\n            inSerialize = false;\n        }\n\n        /// <inheritdoc/>\n        public int Read(Span<byte> destinationSpan, CancellationToken cancellationToken = default) => throw new InvalidOperationException(\"Read is not supported for DiskStreamWriteBuffer\");\n\n        /// <inheritdoc/>\n        public void Dispose()\n        {\n            var localMemoryStream = Interlocked.Exchange(ref pinnedMemoryStream, null);\n            if (localMemoryStream is not null)\n            {\n                // End serialization before disposing the pinned memory stream as it may try to flush final data which would use the pinnedMemoryStream.\n                valueObjectSerializer?.EndSerialize();\n                localMemoryStream.Dispose();\n            }\n        }\n    }\n}","sourceCodeStart":315,"sourceCodeEnd":347,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/storage/Tsavorite/cs/src/core/Allocator/ObjectSerialization/ObjectLogWriter.cs#L315-L347","documentation":"DiskStreamWriteBuffer is write-only; its Read implementation throws InvalidOperationException. It exists to serialize objects into the object log and holds a pinned memory stream for writing only. Reading from it is a misuse — the caller invoked a read-side operation on a write-side buffer.","triggerScenarios":"Calling Read(Span<byte>) on an IStreamBuffer that is actually a DiskStreamWriteBuffer — e.g. deserialization code that received a write buffer from a shared pool or a misrouted buffer reference.","commonSituations":"Generic buffer-pool code calling Read on any returned buffer; a refactor routing a write buffer into a read/deserialize path; shared IStreamBuffer handling not distinguishing buffer direction.","solutions":["Check the buffer type or a CanRead flag before calling Read.","Use distinct pools/types for read vs write buffers so a reader never gets a DiskStreamWriteBuffer.","Ensure the deserialization path receives a DiskStreamReadBuffer, not a write buffer."],"exampleFix":"// before\nint n = buffer.Read(dest, cancellationToken);\n// after\nif (buffer is DiskStreamWriteBuffer)\n    throw new InvalidOperationException(\"Cannot read from a write buffer\");\nint n = buffer.Read(dest, cancellationToken);","handlingStrategy":"type-guard","validationCode":"if (buffer is DiskStreamWriteBuffer) throw new InvalidOperationException(\"Cannot Read from a write buffer\");\nint n = buffer.Read(dest, cancellationToken);","typeGuard":"static bool CanRead(IStreamBuffer b) => b is not DiskStreamWriteBuffer;","tryCatchPattern":null,"preventionTips":["Keep read and write buffer pools separate.","Check buffer direction before invoking read operations."],"tags":["object-log","stream-buffer","write-only","invalid-operation"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}