{"record":{"id":"53696e0790e6e97b","repo":"quickwit-oss/quickwit","slug":"merge-parquet-split-metadata-requires-at-least-one","errorCode":null,"errorMessage":"merge_parquet_split_metadata requires at least one input split","messagePattern":"merge_parquet_split_metadata requires at least one input split","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-parquet-engine/src/merge/metadata_aggregation.rs","lineNumber":57,"sourceCode":"/// agree due to compaction scope grouping / MP-3).\n///\n/// # Preconditions\n///\n/// All input splits must share the same kind, index_uid, partition_id,\n/// sort_fields, and window. In the default case (`mixed_prefix_ok = false`)\n/// they must also share `rg_partition_prefix_len`. In legacy-promotion\n/// mode (`mixed_prefix_ok = true`) the prefix-len equality check is\n/// skipped because inputs come from different prefix buckets — the\n/// output's prefix_len is taken from the writer's KV stamp via\n/// `output.output_rg_partition_prefix_len` (CS-1), so the input-side\n/// equality is no longer load-bearing for the metastore record.\npub fn merge_parquet_split_metadata(\n    inputs: &[ParquetSplitMetadata],\n    output: &MergeOutputFile,\n    mixed_prefix_ok: bool,\n) -> Result<ParquetSplitMetadata> {\n    if inputs.is_empty() {\n        bail!(\"merge_parquet_split_metadata requires at least one input split\");\n    }\n\n    let first = &inputs[0];\n\n    // Validate invariant fields: all inputs must agree on these.\n    for (i, input) in inputs.iter().enumerate().skip(1) {\n        if input.kind != first.kind {\n            bail!(\n                \"input {} has kind {:?}, expected {:?}\",\n                i,\n                input.kind,\n                first.kind\n            );\n        }\n        if input.index_uid != first.index_uid {\n            bail!(\n                \"input {} has index_uid '{}', expected '{}'\",\n                i,","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-parquet-engine/src/merge/metadata_aggregation.rs#L39-L75","documentation":"merge_parquet_split_metadata aggregates Parquet split metadata for a merge and requires at least one input split; it indexes inputs[0] to establish baseline invariant fields, so an empty input slice is rejected up front.","triggerScenarios":"Calling merge_parquet_split_metadata (directly or via the merge handle) with an empty inputs slice, e.g. scheduling a merge after all candidate splits were filtered out.","commonSituations":"A merge task computed against splits that were deleted/consumed before execution; upstream filtering logic removing all inputs; a unit-test edge case.","solutions":["Ensure the merge caller checks for non-empty input and skips the merge instead of invoking it","Fix upstream split selection so empty merge tasks are never scheduled","Add a guard in handle: if inputs.is_empty() { return early/log } before calling the function"],"exampleFix":"// before\nmerge_parquet_split_metadata(&splits, &output, false)?;\n// after\nif splits.is_empty() {\n    return Ok(None); // nothing to merge\n}\nSome(merge_parquet_split_metadata(&splits, &output, false)?)","handlingStrategy":"try-catch","validationCode":"if inputs.is_empty() {\n    // skip merge entirely\n    return Ok(None);\n}","typeGuard":"fn mergeable(inputs: &[ParquetSplitMetadata]) -> bool { !inputs.is_empty() }","tryCatchPattern":"match merge_parquet_split_metadata(&inputs, &output, false) {\n    Err(e) if e.to_string().contains(\"at least one input split\") => {\n        warn!(\"empty merge skipped: {e}\");\n        Ok(None)\n    }\n    other => other.map(Some),\n}","preventionTips":["Filter out empty merge tasks before scheduling them","Check that candidate splits still exist between scheduling and execution","Assert non-empty inputs in tests covering merge orchestration"],"tags":["parquet","merge","precondition","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}