microsoft/garnet · error · NotSupportedException
Stream does not support get_Position.
Error message
Stream does not support get_Position.
What it means
PinnedMemoryStream is forward-only and chunked, so it cannot report a seekable Position; the Position getter throws NotSupportedException. Position only has meaning for seekable streams, which this is not.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/ObjectSerialization/PinnedMemoryStream.cs:76
streamBuffer.FlushAndReset(cancellationToken);
return Task.CompletedTask;
}
catch (Exception ex)
{
return Task.FromException(ex);
}
}
/// <summary>The amount of data in the internal streamBuffer. Not supported because we chunk and thus may not have all data.</summary>
public override long Length
{
get => throw new NotSupportedException("Stream does not support get_Length.");
}
/// <summary>The current position of the stream seeking; not supported</summary>
public override long Position
{
get => throw new NotSupportedException("Stream does not support get_Position.");
set => throw new NotSupportedException("Stream does not support set_Position.");
}
/// <summary>Copy data from the internal streamBuffer into the buffer; the streamBuffer handles Flush, Reset, and Read more
/// (e.g. from disk or network) as needed.</summary>
/// <param name="buffer">Buffer to copy the bytes into.</param>
/// <param name="offset">Index in the buffer to start copying to.</param>
/// <param name="count">Desired number of bytes to copy to the buffer.</param>
/// <returns>Number of bytes actually read.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);
return streamBuffer.Read(new Span<byte>(buffer, offset, count));
}
/// <summary>Copy data from the internal streamBuffer into the destination span; the streamBuffer handles Flush, Reset, and Read more
/// (e.g. from disk or network) as needed.</summary>
public override int Read(Span<byte> destinationSpan) => streamBuffer.Read(destinationSpan);View on GitHub (pinned to 951b0fc683)
Solutions
- Maintain your own byte counter instead of reading stream.Position.
- Avoid components that require Position on the object-log serialization stream.
- If Position is unavoidable, serialize into a MemoryStream and copy forward, accepting the trade-off.
Example fix
// before var pos = w.BaseStream.Position; // throws // after long written = 0; written += sizeof(int); w.Write(_x);
Defensive patterns
Strategy: validation
Validate before calling
if (stream is PinnedMemoryStream) throw new NotSupportedException("PinnedMemoryStream has no Position; track bytes manually");
var pos = stream.Position; Type guard
static bool HasPosition(Stream s) => s is not PinnedMemoryStream;
Prevention
- Maintain your own offset counter instead of reading stream.Position.
- Avoid framing/serializers that require a Position on chunked streams.
When it happens
Trigger: Any code that reads the Position of a stream backed by PinnedMemoryStream — serializers, framing helpers, or logging code that accesses BaseStream.Position.
Common situations: A custom serializer recording offsets via stream.Position; wrapping the stream in an API that probes Position; copy code that uses Position to track progress.
Related errors
- Stream does not support get_Length.
- Stream does not support Seek.
- 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/87e5a0b8e01c5c39.
Report an issue: GitHub.