tui-cs/Terminal.Gui · error · ArgumentException

The source stream must be seekable (CanSeek property)

Error message

The source stream must be seekable (CanSeek property)

What it means

Thrown by the HexView.Source setter when the supplied Stream has CanSeek == false. HexView must seek arbitrarily through the byte source to render any address, apply edits, and navigate, so a non-seekable stream (e.g. a network pipe or unbuffered console input) cannot back the view. The check is a hard precondition in the setter, before any state is mutated.

Source

Thrown at Terminal.Gui/Views/HexView.cs:320

    public void DiscardEdits () => _edits = new SortedDictionary<long, byte> ();

    private Stream? _source;

    /// <summary>
    ///     Sets or gets the <see cref="Stream"/> the <see cref="HexView"/> is operating on; the stream must support
    ///     seeking ( <see cref="Stream.CanSeek"/> == true).
    /// </summary>
    /// <value>The source.</value>
    public Stream? Source
    {
        get => _source;
        set
        {
            ArgumentNullException.ThrowIfNull (value);

            if (!value.CanSeek)
            {
                throw new ArgumentException (@"The source stream must be seekable (CanSeek property)");
            }

            DiscardEdits ();
            _source = value;
            SetBytesPerLine ();

            if (Address > _source.Length)
            {
                Address = 0;
            }

            SetNeedsLayout ();
            SetNeedsDraw ();
        }
    }

    /// <summary>The bytes length per line.</summary>
    public int BytesPerLine

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Buffer the source into a MemoryStream first: var ms = new MemoryStream(); source.CopyTo(ms); ms.Position = 0; hexView.Source = ms;
  2. If the data is file-backed, open with File.OpenRead which is always seekable.
  3. Subclass the stream and override CanSeek => true only if you genuinely implement Position/Seek/Length.
  4. Pre-validate stream.CanSeek before assigning to Source and surface a user-facing message instead of letting the library throw.

Example fix

// before
using var netStream = httpClient.GetStreamAsync(url).Result;
hexView.Source = netStream; // throws 160

// after
using var netStream = httpClient.GetStreamAsync(url).Result;
using var ms = new MemoryStream();
netStream.CopyTo(ms);
ms.Position = 0;
hexView.Source = ms;
Defensive patterns

Strategy: validation

Validate before calling

if (stream is null || !stream.CanSeek)
{
    // buffer or reject before assigning
    using var ms = new MemoryStream();
    stream?.CopyTo(ms);
    ms.Position = 0;
    hexView.Source = ms;
    return;
}
hexView.Source = stream;

Type guard

static bool IsUsableForHexView(Stream? s) => s is { CanSeek: true };

Prevention

When it happens

Trigger: Assigning HexView.Source to a Stream whose CanSeek is false, such as a NetworkStream, an unbuffered Console.OpenStandardInput(), a PipeReader-as-stream, or a DeflateStream/GZipStream read stream. Also happens when wrapping a stream that loses seekability after construction.

Common situations: Loading bytes directly from a socket or HTTP response without buffering first; using a forward-only crypto/decoder stream; unit tests feeding a fake stream that forgets to override CanSeek to true.

Related errors


AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13). Data as JSON: /api/errors/f6000bba195d1a52. Report an issue: GitHub.