nautechsystems/nautilus_trader · error
CSV file is empty
Error message
CSV file is empty
What it means
TardisBookUpdateData::new requires at least one CSV record to determine the instrument ID and price/size precision defaults. The library throws this when the CSV file contains zero records (only a header or completely empty), since there is no first record to deserialize into TardisBookUpdateRecord.
Source
Thrown at crates/adapters/tardis/src/csv/stream.rs:387
///
/// # Errors
///
/// Returns an error if the file cannot be opened or read.
fn new<P: AsRef<Path>>(
filepath: P,
chunk_size: usize,
price_precision: Option<u8>,
size_precision: Option<u8>,
instrument_id: Option<InstrumentId>,
limit: Option<usize>,
) -> anyhow::Result<Self> {
let mut reader = create_csv_reader(&filepath)?;
let mut record = StringRecord::new();
let first_record = if reader.read_record(&mut record)? {
record.deserialize::<TardisBookUpdateRecord>(None)?
} else {
anyhow::bail!("CSV file is empty");
};
let final_instrument_id = instrument_id
.unwrap_or_else(|| parse_instrument_id(&first_record.exchange, first_record.symbol));
let (final_price_precision, final_size_precision) =
if let (Some(price_prec), Some(size_prec)) = (price_precision, size_precision) {
// Both precisions provided, use them directly
(price_prec, size_prec)
} else {
// One or both precisions missing, detect from sample including first record
let (detected_price, detected_size) =
Self::detect_precision_from_sample(&mut reader, &mut record, 10_000);
(
price_precision.unwrap_or(detected_price),
size_precision.unwrap_or(detected_size),
)
};View on GitHub (pinned to 18893faf8b)
Solutions
- Check the file has data rows: `wc -l file.csv` (should be > 1 for a header + rows)
- Re-download the Tardis dataset for the correct date/venue/symbol
- Point TardisBookUpdateData::new at the correct non-empty CSV file
- If instrument_id/precisions are provided, verify the intended file wasn't replaced by an empty one
Example fix
// before let data = TardisBookUpdateData::new(path, None, None, None)?; // empty file // after assert!(std::fs::metadata(&path)?.len() > 0, "CSV file is empty"); let data = TardisBookUpdateData::new(path, None, None, None)?;
Defensive patterns
Strategy: validation
Validate before calling
fn csv_has_data(path: &Path) -> anyhow::Result<bool> {
let content = std::fs::read_to_string(path)?;
Ok(content.lines().skip_while(|l| l.trim().is_empty()).count() > 1) // header + rows
}
assert!(csv_has_data(&path)?, "CSV has no data rows"); Try / catch
let data = match TardisBookUpdateData::new(&path, None, None, None) {
Ok(d) => d,
Err(e) if e.to_string().contains("CSV file is empty") => {
eprintln!("{} has no records; check the download", path.display());
return Err(e);
}
Err(e) => return Err(e),
}; Prevention
- Check `wc -l` on CSVs before loading
- Validate Tardis downloads (row counts) after each fetch
- Watch for truncated/interrupted downloads that drop all rows
When it happens
Trigger: Constructing TardisBookUpdateData::new with a filepath whose CSV has a header but no data rows, or is entirely empty (0 bytes).
Common situations: Tardis download returned an empty dataset for the requested date/venue; a filtered export removed all rows; the user pointed at the wrong (empty) file; an interrupted download produced a truncated file.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- unrecognized side '{side}'
- options_chain instrument derivation supports Deribit only, r
- Failed to open file '{}' after {max_retries} attempts: {e}
- File too small to be a valid gzip file
- Failed to read gzip header from '{}' after {MAX_RETRIES} att
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e1afa1e91cc83378.
Report an issue: GitHub.