dotnet/machinelearning · error · System.ArgumentException
Expected a seekable stream
Error message
Expected a seekable stream
What it means
LoadCsv requires a seekable stream because the CSV reader needs to rewind/re-read rows for header detection and type guessing. If csvStream.CanSeek is false, it throws ArgumentException(Strings.NonSeekableStream, nameof(csvStream)) = 'Expected a seekable stream'. Non-seekable streams (e.g. network or stdin streams) cannot be used directly.
Source
Thrown at src/Microsoft.Data.Analysis/DataFrame.IO.cs:576
/// <param name="dataTypes">column types (can be empty)</param>
/// <param name="numberOfRowsToRead">number of rows to read not including the header(if present)</param>
/// <param name="guessRows">number of rows used to guess types</param>
/// <param name="addIndexColumn">add one column with the row index</param>
/// <param name="encoding">The character encoding. Defaults to UTF8 if not specified</param>
/// <param name="renameDuplicatedColumns">If set to true, columns with repeated names are auto-renamed.</param>
/// <param name="cultureInfo">culture info for formatting values</param>
/// <param name="guessTypeFunction">function used to guess the type of a column based on its values</param>
/// <returns><see cref="DataFrame"/></returns>
public static DataFrame LoadCsv(Stream csvStream,
char separator = ',', bool header = true,
string[] columnNames = null, Type[] dataTypes = null,
long numberOfRowsToRead = -1, int guessRows = 10, bool addIndexColumn = false,
Encoding encoding = null, bool renameDuplicatedColumns = false, CultureInfo cultureInfo = null,
Func<IEnumerable<string>, Type> guessTypeFunction = null)
{
if (!csvStream.CanSeek)
{
throw new ArgumentException(Strings.NonSeekableStream, nameof(csvStream));
}
if (dataTypes == null && guessRows <= 0)
{
throw new ArgumentException(string.Format(Strings.ExpectedEitherGuessRowsOrDataTypes, nameof(guessRows), nameof(dataTypes)));
}
WrappedStreamReaderOrStringReader wrappedStreamReaderOrStringReader = new WrappedStreamReaderOrStringReader(csvStream, encoding ?? Encoding.UTF8);
return ReadCsvLinesIntoDataFrame(wrappedStreamReaderOrStringReader, separator, header, columnNames, dataTypes, numberOfRowsToRead, guessRows, addIndexColumn, renameDuplicatedColumns, cultureInfo, guessTypeFunction);
}
/// <summary>
/// Writes a DataFrame into a CSV.
/// </summary>
/// <param name="dataFrame"><see cref="DataFrame"/></param>
/// <param name="path">CSV file path</param>
/// <param name="separator">column separator</param>
/// <param name="header">has a header or not</param>View on GitHub (pinned to 7b76e69cf9)
Solutions
- Copy the stream into a MemoryStream first (stream.CopyTo(ms); ms.Position = 0), then LoadCsv from the MemoryStream
- Write the input to a temporary file and use the file-path LoadCsv overload
- If the source is HTTP, read the full body into memory or a file before parsing
- Buffer with a seekable wrapper only if buffering is acceptable memory-wise; otherwise stream-parse manually
Example fix
// before var df = DataFrame.LoadCsv(responseStream); // after using var ms = new MemoryStream(); responseStream.CopyTo(ms); ms.Position = 0; var df = DataFrame.LoadCsv(ms);
Defensive patterns
Strategy: validation
Validate before calling
if (!stream.CanSeek) { var ms = new MemoryStream(); stream.CopyTo(ms); ms.Position = 0; stream = ms; } Try / catch
try { return DataFrame.LoadCsv(csvStream); } catch (ArgumentException ex) when (ex.Message.Contains("seekable")) { using var ms = new MemoryStream(); csvStream.CopyTo(ms); ms.Position = 0; return DataFrame.LoadCsv(ms); } Prevention
- Check Stream.CanSeek before calling LoadCsv
- Buffer network/pipe streams into MemoryStream or a temp file
- Prefer the file-path LoadCsv overload for non-seekable sources
When it happens
Trigger: Passing a non-seekable Stream — the raw body stream of an HTTP response, Console.OpenStandardInput(), a decryption stream, or a pipe — to DataFrame.LoadCsv.
Common situations: Reading CSV directly from HttpResponse content stream or a WebSocket; piping data via stdin; wrapping a decompressing GZipStream over a network stream where CanSeek is false.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Expected either {0} or {1} to be provided
- Decimal separator cannot match the column separator
- LessColumnsThatExpected
- Exception of type 'System.ArgumentException' was thrown.
- kind
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/746e3693263d4973.
Report an issue: GitHub.