{"record":{"id":"0bbfb502c9fff3b0","repo":"influxdata/influxdb","slug":"tried-to-serialize-a-parquet-file-with-no-rows","errorCode":null,"errorMessage":"tried to serialize a parquet file with no rows","messagePattern":"tried to serialize a parquet file with no rows","errorType":"error_code","errorClass":"PersisterError","httpStatus":null,"severity":"warning","filePath":"influxdb3_write/src/persister.rs","lineNumber":62,"sourceCode":"use parquet::file::metadata::ParquetMetaData;\nuse parquet::file::properties::WriterProperties;\nuse tokio::sync::Semaphore;\n\n#[derive(Debug, thiserror::Error)]\npub enum PersisterError {\n    #[error(\"datafusion error: {0}\")]\n    DataFusion(#[from] DataFusionError),\n\n    #[error(\"serde_json error: {0}\")]\n    SerdeJson(#[from] serde_json::Error),\n\n    #[error(\"object_store error: {0}\")]\n    ObjectStore(#[from] object_store::Error),\n\n    #[error(\"parquet error: {0}\")]\n    ParquetError(#[from] parquet::errors::ParquetError),\n\n    #[error(\"tried to serialize a parquet file with no rows\")]\n    NoRows,\n\n    #[error(\"parse int error: {0}\")]\n    ParseInt(#[from] std::num::ParseIntError),\n\n    #[error(\"unexpected persister error: {0:?}\")]\n    Unexpected(#[from] anyhow::Error),\n\n    #[error(\"table snapshot persistence task panicked: {0}\")]\n    TableSnapshotPersistenceTaskFailed(#[source] tokio::task::JoinError),\n\n    #[error(\"snapshot manifest parse task panicked: {0}\")]\n    SnapshotParseTaskFailed(#[source] tokio::task::JoinError),\n\n    #[error(\"table index error: {0}\")]\n    TableIndexPathError(#[source] crate::paths::PathError),\n\n    #[error(\"object meta is missing filename\")]","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_write/src/persister.rs#L44-L80","documentation":"PersisterError::NoRows is returned when the Persister is asked to serialize a parquet file from a RecordBatch that contains zero rows. Parquet persistence is only meaningful for non-empty batches, so an empty batch is rejected explicitly rather than producing an empty file.","triggerScenarios":"Calling the persister's parquet-write path with an empty RecordBatch — e.g. persisting a table snapshot or query result that filtered everything out or a table with no data at flush time.","commonSituations":"Compaction/snapshot logic running on a table with no rows; a query predicate that matches nothing being fed to persist; a bug in upstream buffering yielding empty batches.","solutions":["Skip persisting when `batch.num_rows() == 0` before calling the persister.","Trace why an empty batch reached the persister (empty table vs over-aggressive filter).","Guard snapshot/compaction tasks to no-op on empty tables."],"exampleFix":"// before\npersister.persist(batch).await?;\n// after\nif batch.num_rows() > 0 {\n    persister.persist(batch).await?;\n}","handlingStrategy":"validation","validationCode":"if batch.num_rows() == 0 {\n    return Ok(()); // nothing to persist\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always check num_rows() before handing a RecordBatch to the persister.","No-op snapshot/compaction tasks for empty tables.","Assert in unit tests that flushing an empty table does not call persist."],"tags":["parquet","empty-input","validation","rust"],"backgroundTag":"empty-required-field","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}