{"record":{"id":"afa231e823c97e0d","repo":"nautechsystems/nautilus_trader","slug":"decode-custom-batches-to-data-called-with-empty-ba","errorCode":null,"errorMessage":"decode_custom_batches_to_data called with empty batches","messagePattern":"decode_custom_batches_to_data called with empty batches","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/persistence/src/backend/custom.rs","lineNumber":243,"sourceCode":"    }\n}\n\n/// Decodes multiple `RecordBatches` (e.g. from custom data files) into a single `Vec<Data>`.\n/// Optionally replaces `ts_init` column with `ts_event` before decoding each batch.\n///\n/// # Errors\n///\n/// Returns an error if any batch fails to decode.\npub fn decode_custom_batches_to_data(\n    batches: Vec<RecordBatch>,\n    use_ts_event_for_ts_init: bool,\n) -> anyhow::Result<Vec<Data>> {\n    let mut file_data = Vec::new();\n    let schema = batches\n        .first()\n        .map(arrow::array::RecordBatch::schema)\n        .ok_or_else(|| {\n            anyhow::anyhow!(\"decode_custom_batches_to_data called with empty batches\")\n        })?;\n\n    for mut batch in batches {\n        if use_ts_event_for_ts_init {\n            let column_names: Vec<String> =\n                schema.fields().iter().map(|f| f.name().clone()).collect();\n\n            if let (Some(ts_event_idx), Some(ts_init_idx)) = (\n                column_names.iter().position(|n| n == \"ts_event\"),\n                column_names.iter().position(|n| n == \"ts_init\"),\n            ) {\n                let mut new_columns = batch.columns().to_vec();\n                new_columns[ts_init_idx] = new_columns[ts_event_idx].clone();\n                batch = RecordBatch::try_new(schema.clone(), new_columns)\n                    .map_err(|e| anyhow::anyhow!(\"Failed to create new batch: {e}\"))?;\n            }\n        }\n        let metadata = batch.schema().metadata().clone();","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/persistence/src/backend/custom.rs#L225-L261","documentation":"Thrown by decode_custom_batches_to_data when it is called with an empty iterator of RecordBatches. The function derives the schema from the first batch, so with zero batches there is nothing to decode and no schema to consult; the call is treated as a programming error rather than returning an empty result.","triggerScenarios":"Calling decode_custom_batches_to_data with an empty Vec of batches — e.g. a file query returned no record batches, or write/read logic filtered out all batches before the call.","commonSituations":"Reading a catalog file that contained zero rows after a filtered query; code paths that pass batches.first()-derived collections without checking emptiness; handling of empty feather files produced by failed writes.","solutions":["Guard the caller: check !batches.is_empty() before calling decode_custom_batches_to_data and return an empty Vec<Data> instead.","Fix the upstream query/write logic if empty files are being produced unexpectedly.","If an empty result is legitimate, treat it as no-op at the call site rather than invoking the decoder."],"exampleFix":"// before\nlet data = decode_custom_batches_to_data(&batches, false, true)?;\n// after\nlet data = if batches.is_empty() {\n    Vec::new()\n} else {\n    decode_custom_batches_to_data(&batches, false, true)?\n};","handlingStrategy":"validation","validationCode":"if batches.is_empty() { return Ok(Vec::new()); }","typeGuard":"fn non_empty(batches: &[RecordBatch]) -> Option<&[RecordBatch]> {\n    (!batches.is_empty()).then_some(batches)\n}","tryCatchPattern":"match decode_custom_batches_to_data(&batches, false, true) {\n    Ok(data) => use(data),\n    Err(e) if e.to_string().contains(\"empty batches\") => return Ok(Vec::new()),\n    Err(e) => return Err(e),\n}","preventionTips":["Check batch count before decoding","Treat empty query results as legitimate empty data","Fix writers that emit zero-batch files unexpectedly","Return early from read helpers when no files matched the query"],"tags":["rust","persistence","empty-input"],"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"}