{"record":{"id":"2030cac68dbb5575","repo":"quickwit-oss/quickwit","slug":"input-has-partition-id-expected","errorCode":null,"errorMessage":"input {} has partition_id {}, expected {}","messagePattern":"input (.+?) has partition_id (.+?), expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-parquet-engine/src/merge/metadata_aggregation.rs","lineNumber":81,"sourceCode":"    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,\n                input.index_uid,\n                first.index_uid\n            );\n        }\n        if input.partition_id != first.partition_id {\n            bail!(\n                \"input {} has partition_id {}, expected {}\",\n                i,\n                input.partition_id,\n                first.partition_id\n            );\n        }\n        if input.sort_fields != first.sort_fields {\n            bail!(\n                \"input {} has sort_fields '{}', expected '{}'\",\n                i,\n                input.sort_fields,\n                first.sort_fields\n            );\n        }\n        if input.window != first.window {\n            bail!(\n                \"input {} has window {:?}, expected {:?}\",\n                i,","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-parquet-engine/src/merge/metadata_aggregation.rs#L63-L99","documentation":"merge_parquet_split_metadata requires all input splits to share the same `partition_id`. This bail fires when input i's partition_id differs from inputs[0]'s. Merging across partitions would corrupt the partition attribution of the output split, so this is a hard precondition enforced before assembling output metadata.","triggerScenarios":"Calling merge_parquet_split_metadata with inputs selected across different partition ids — e.g. a merge policy that only sorts by index_uid and time range but not partition_id, or split metadata loaded for the wrong partition task.","commonSituations":"Merge scheduler bug after partitioning scheme changes; repartitioning an index leaves old splits assigned to old partition ids that a broad query pulls into one merge task; hand-built test metadata mixing partition ids.","solutions":["Fix the merge selection query to filter by partition_id as well as index_uid and time range.","After a repartitioning operation, re-tag or re-split legacy splits so each candidate set is single-partition.","Add an assertion/filter at task-assignment time so mixed-partition candidate lists are rejected earlier with clearer context.","In tests, generate all input splits from one partition_id constant."],"exampleFix":"// before\nif input.index_uid != first.index_uid { bail!(...); }\n// after (partition check already exists; ensure selection filters too)\nSELECT ... WHERE index_uid = $1 AND partition_id = $2 AND time_range && $3","handlingStrategy":"validation","validationCode":"fn single_partition(inputs: &[ParquetSplitMetadata]) -> bool {\n    inputs.iter().all(|s| s.partition_id == inputs[0].partition_id)\n}","typeGuard":"fn same_partition(inputs: &[ParquetSplitMetadata]) -> Option<u32> {\n    let pid = inputs.first()?.partition_id;\n    inputs.iter().all(|s| s.partition_id == pid).then_some(pid)\n}","tryCatchPattern":"if let Err(e) = merge_parquet_split_metadata(&inputs, &output, mixed) {\n    if e.to_string().contains(\"partition_id\") {\n        warn!(\"mixed-partition merge rejected: {e:#}; re-grouping by partition\");\n        return regroup_and_retry(inputs);\n    }\n    return Err(e);\n}","preventionTips":["Filter by partition_id in every merge candidate query.","After repartitioning, run a migration so old splits don't linger with old partition ids.","Group merge tasks with a composite key (index_uid, partition_id, ...)."],"tags":["rust","merge","partition","invariant-violation"],"backgroundTag":"internal-invariant-violation","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}