{"record":{"id":"e1afa1e91cc83378","repo":"nautechsystems/nautilus_trader","slug":"csv-file-is-empty","errorCode":null,"errorMessage":"CSV file is empty","messagePattern":"CSV file is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/tardis/src/csv/stream.rs","lineNumber":387,"sourceCode":"    ///\n    /// # Errors\n    ///\n    /// Returns an error if the file cannot be opened or read.\n    fn new<P: AsRef<Path>>(\n        filepath: P,\n        chunk_size: usize,\n        price_precision: Option<u8>,\n        size_precision: Option<u8>,\n        instrument_id: Option<InstrumentId>,\n        limit: Option<usize>,\n    ) -> anyhow::Result<Self> {\n        let mut reader = create_csv_reader(&filepath)?;\n        let mut record = StringRecord::new();\n\n        let first_record = if reader.read_record(&mut record)? {\n            record.deserialize::<TardisBookUpdateRecord>(None)?\n        } else {\n            anyhow::bail!(\"CSV file is empty\");\n        };\n\n        let final_instrument_id = instrument_id\n            .unwrap_or_else(|| parse_instrument_id(&first_record.exchange, first_record.symbol));\n\n        let (final_price_precision, final_size_precision) =\n            if let (Some(price_prec), Some(size_prec)) = (price_precision, size_precision) {\n                // Both precisions provided, use them directly\n                (price_prec, size_prec)\n            } else {\n                // One or both precisions missing, detect from sample including first record\n                let (detected_price, detected_size) =\n                    Self::detect_precision_from_sample(&mut reader, &mut record, 10_000);\n                (\n                    price_precision.unwrap_or(detected_price),\n                    size_precision.unwrap_or(detected_size),\n                )\n            };","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/tardis/src/csv/stream.rs#L369-L405","documentation":"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.","triggerScenarios":"Constructing TardisBookUpdateData::new with a filepath whose CSV has a header but no data rows, or is entirely empty (0 bytes).","commonSituations":"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.","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"],"exampleFix":"// before\nlet data = TardisBookUpdateData::new(path, None, None, None)?;  // empty file\n// after\nassert!(std::fs::metadata(&path)?.len() > 0, \"CSV file is empty\");\nlet data = TardisBookUpdateData::new(path, None, None, None)?;","handlingStrategy":"validation","validationCode":"fn csv_has_data(path: &Path) -> anyhow::Result<bool> {\n    let content = std::fs::read_to_string(path)?;\n    Ok(content.lines().skip_while(|l| l.trim().is_empty()).count() > 1) // header + rows\n}\nassert!(csv_has_data(&path)?, \"CSV has no data rows\");","typeGuard":null,"tryCatchPattern":"let data = match TardisBookUpdateData::new(&path, None, None, None) {\n    Ok(d) => d,\n    Err(e) if e.to_string().contains(\"CSV file is empty\") => {\n        eprintln!(\"{} has no records; check the download\", path.display());\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Check `wc -l` on CSVs before loading","Validate Tardis downloads (row counts) after each fetch","Watch for truncated/interrupted downloads that drop all rows"],"tags":["csv","empty-file","validation","tardis"],"backgroundTag":"empty-required-field","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}