microsoft/garnet · error · InvalidOperationException
Stream does not support Seek.
Error message
Stream does not support Seek.
What it means
PinnedMemoryStream is non-seekable: it streams data through an IStreamBuffer in chunks, so seeking to an arbitrary offset is impossible. Its Seek override throws InvalidOperationException. The stream is forward-only by construction.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/ObjectSerialization/PinnedMemoryStream.cs:124
{
return new ValueTask<int>(Read(buffer.Span));
}
catch (Exception ex)
{
return ValueTask.FromException<int>(ex);
}
}
/// <summary>Returns the byte at the current streamBuffer position and advances the position</summary>
/// <returns>The byte read (as an int)</returns>
public override unsafe int ReadByte()
{
byte b = default;
return streamBuffer.Read(new Span<byte>(ref b)) > 0 ? b : -1;
}
/// <summary>Seeking is not supported in this stream.</summary>
public override long Seek(long offset, SeekOrigin loc) => throw new InvalidOperationException("Stream does not support Seek.");
/// <summary>Seeking is not supported in this stream.</summary>
public override void SetLength(long value) => throw new InvalidOperationException("Stream does not support SetLength.");
/// <summary>Write the buffer to the stream; the streamBuffer handles Flush, Reset, and Writing iteratively
/// (e.g. to disk or network) as needed.</summary>
/// <param name="buffer">Buffer to write the bytes from.</param>
/// <param name="offset">Index in the buffer to start writing from.</param>
/// <param name="count">Desired number of bytes to write from the buffer.</param>
public override void Write(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);
streamBuffer.Write(new ReadOnlySpan<byte>(buffer, offset, count));
}
/// <summary>Write the buffer to the stream; the streamBuffer handles Flush, Reset, and Writing iteratively
/// (e.g. to disk or network) as needed.</summary>
public override void Write(ReadOnlySpan<byte> destinationSpan) => streamBuffer.Write(destinationSpan);View on GitHub (pinned to 951b0fc683)
Solutions
- Write length prefixes without seeking: reserve space by buffering the record first, or compute the length before writing.
- Do not call Seek on the object-log serialization stream.
- If a downstream component must seek, serialize into a MemoryStream and then copy the bytes forward into the Tsavorite stream.
Example fix
// before long pos = w.BaseStream.Position; w.Write(payload); w.BaseStream.Seek(pos, SeekOrigin.Begin); // throws // after w.Write(payload.Length); w.Write(payload);
Defensive patterns
Strategy: validation
Validate before calling
if (!stream.CanSeek) throw new NotSupportedException("Stream is not seekable; use forward-only writes");
stream.Seek(offset, origin); Type guard
static bool CanSeekSafe(Stream s) => s.CanSeek;
Prevention
- Write length prefixes without seeking: buffer first or compute length before writing.
- Check CanSeek before any Seek call on a stream you don't own.
- Avoid patching headers by rewinding on the object-log serialization stream.
When it happens
Trigger: Code that calls Seek on a PinnedMemoryStream-backed stream — e.g. a serializer/framework that rewinds, length-prefixed framing that seeks back to patch a header, or a copy routine that seeks.
Common situations: A custom IHeapObject serializer that seeks back to write a length prefix; wrapping PinnedMemoryStream in a component that rewinds (compression, crypto with seek); a BinaryWriter pattern that seeks to finalize headers.
Related errors
- Stream does not support get_Length.
- Stream does not support get_Position.
- Advancing position by {size:N} bytes exceeds maximum object
- Object serialized size currently at {valueObjectBytesWritten
- Stream does not support SetLength.
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/abf5676ce3051d0e.
Report an issue: GitHub.