{"record":{"id":"cbb5f53fad6a8d25","repo":"databendlabs/databend","slug":"transform-aggregator-hash-table-already-moved-ou-cbb5f5","errorCode":null,"errorMessage":"[TRANSFORM-AGGREGATOR] Hash table already moved out in finish","messagePattern":"\\[TRANSFORM-AGGREGATOR\\] Hash table already moved out in finish","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/service/src/pipelines/processors/transforms/aggregator/transform_aggregate_partial.rs","lineNumber":247,"sourceCode":"impl AccumulatingTransform for TransformPartialAggregate {\n    const NAME: &'static str = \"TransformPartialAggregate\";\n\n    fn transform(&mut self, block: DataBlock) -> Result<Vec<DataBlock>> {\n        self.execute_one_block(block)?;\n\n        if self.settings.check_spill() {\n            self.spill_out()?;\n        }\n\n        Ok(vec![])\n    }\n\n    fn on_finish(&mut self, output: bool) -> Result<Vec<DataBlock>> {\n        Ok(match std::mem::take(&mut self.hash_table) {\n            HashTable::MovedOut => match !output {\n                true => vec![],\n                false => {\n                    unreachable!(\"[TRANSFORM-AGGREGATOR] Hash table already moved out in finish\")\n                }\n            },\n            HashTable::AggregateHashTable(hashtable) => {\n                let mut blocks = self.spillers.finish()?;\n\n                self.statistics.log_finish_statistics(&hashtable);\n\n                let payloads = hashtable\n                    .payload\n                    .into_bucket_payloads()\n                    .map(|(bucket, payload)| AggregatePayload {\n                        bucket: bucket as isize,\n                        payload,\n                        max_partition_count: 0,\n                    })\n                    .collect::<Vec<_>>();\n                blocks.push(DataBlock::empty_with_meta(\n                    AggregateMeta::create_partitioned(","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/service/src/pipelines/processors/transforms/aggregator/transform_aggregate_partial.rs#L229-L265","documentation":"TransformPartialAggregate::on_finish takes the hash table via std::mem::take; if it finds HashTable::MovedOut on a path where output is expected (!output is false branch), it hits unreachable!, meaning the table was already moved out before finish. It guards that finish is reached exactly once with the table still present.","triggerScenarios":"on_finish runs twice, or the table was moved out earlier (spill_out/execute paths) while output was still required — caused by pipeline driver bugs, double process/finish, or retry logic re-invoking the transform.","commonSituations":"Executor regressions in AccumulatingTransform lifecycle; query retries replaying finish; custom pipelines mis-wiring event ordering.","solutions":["Upgrade to a version with the lifecycle fix and retry","Audit any custom pipeline for duplicate on_finish calls","File a bug with stack trace and query profile if reproducible on one version"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn finishable(ht: &HashTable, output: bool) -> bool {\n    !output || matches!(ht, HashTable::AggregateHashTable(_))\n}","tryCatchPattern":"match res {\n    Err(e) if e.message().contains(\"Hash table already moved out in finish\") => {\n        // query abort; retry on fixed version; file with stack trace\n    }\n    ...\n}","preventionTips":["Guarantee on_finish runs exactly once per transform lifecycle","Keep hash-table take operations confined to on_finish only","Add executor tests covering finish-before-input-drained and double-finish cases","Keep pipeline retry logic from replaying finished transforms"],"tags":["internal","aggregation","state-machine","unreachable"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}