dotnet/machinelearning · error · System.ArgumentException
Decimal separator cannot match the column separator
Error message
Decimal separator cannot match the column separator
What it means
SaveCsv writes columns separated by 'separator'; if the culture's NumberDecimalSeparator equals that separator, numeric values would be indistinguishable from column boundaries, corrupting the CSV. SaveCsv therefore throws ArgumentException('Decimal separator cannot match the column separator').
Solutions
- Pass a cultureInfo whose decimal separator differs from the separator, e.g. CultureInfo.InvariantCulture
- Use ';' as the field separator when targeting a comma-decimal culture
- Force the decimal format explicitly instead of relying on CurrentCulture
- Pre-validate the two separators in caller code before calling SaveCsv
Example fix
// before df.SaveCsv(path, separator: ','); // de-DE machine: decimal sep is ',' // after df.SaveCsv(path, separator: ',', cultureInfo: CultureInfo.InvariantCulture);
Defensive patterns
Strategy: validation
Validate before calling
var ci = cultureInfo ?? CultureInfo.CurrentCulture;
if (ci.NumberFormat.NumberDecimalSeparator.Equals(separator.ToString()))
cultureInfo = CultureInfo.InvariantCulture; Try / catch
try { df.SaveCsv(path, separator: separator, cultureInfo: cultureInfo); } catch (ArgumentException ex) when (ex.Message.Contains("Decimal separator")) { df.SaveCsv(path, separator: ';', cultureInfo: cultureInfo); } Prevention
- Always pass CultureInfo.InvariantCulture for machine-readable CSV
- Prefer ';' separators in comma-decimal locales
- Test CSV exports under multiple regional settings
When it happens
Trigger: Calling SaveCsv with separator ',' (or '.') combined with a culture whose NumberDecimalSeparator is the same character — classically a European culture where the decimal separator is ',' while writing comma-separated CSV, e.g. SaveCsv(df, path, separator: ',', cultureInfo: new CultureInfo("de-DE")).
Common situations: European locales writing comma-delimited CSV; hardcoding separator ',' while relying on CultureInfo.CurrentCulture that uses ',' decimals; machines with regional settings differing from dev machines.
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 a seekable stream
- Expected either or to be provided
- A quoted field opened on line
- Array lengths are mistmached
- Blob for normalization rule is broken.
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/09475b8f3dc32d58.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.Data.Analysis/DataFrame.IO.cs:663
/// </summary>
/// <param name="dataFrame"><see cref="DataFrame"/></param>
/// <param name="csvStream">stream of CSV data to be write out</param>
/// <param name="separator">column separator</param>
/// <param name="header">has a header or not</param>
/// <param name="encoding">the character encoding. Defaults to UTF8 if not specified</param>
/// <param name="cultureInfo">culture info for formatting values</param>
public static void SaveCsv(DataFrame dataFrame, Stream csvStream,
char separator = ',', bool header = true,
Encoding encoding = null, CultureInfo cultureInfo = null)
{
if (cultureInfo is null)
{
cultureInfo = CultureInfo.CurrentCulture;
}
if (cultureInfo.NumberFormat.NumberDecimalSeparator.Equals(separator.ToString()))
{
throw new ArgumentException("Decimal separator cannot match the column separator");
}
if (encoding is null)
{
encoding = Encoding.ASCII;
}
using (StreamWriter csvFile = new StreamWriter(csvStream, encoding, bufferSize: DefaultStreamReaderBufferSize, leaveOpen: true))
{
if (dataFrame != null)
{
if (header)
{
SaveHeader(csvFile, dataFrame.Columns.GetColumnNames(), separator);
}
var record = new StringBuilder();
View on GitHub (pinned to 7b76e69cf9)