databendlabs/databend · error
[TRANSFORM-AGGREGATOR] Hash table already moved out in…
Error message
[TRANSFORM-AGGREGATOR] Hash table already moved out in finish
What it means
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.
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
Defensive patterns
Strategy: try-catch
Type guard
fn finishable(ht: &HashTable, output: bool) -> bool {
!output || matches!(ht, HashTable::AggregateHashTable(_))
} Try / catch
match res {
Err(e) if e.message().contains("Hash table already moved out in finish") => {
// query abort; retry on fixed version; file with stack trace
}
...
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Executor regressions in AccumulatingTransform lifecycle; query retries replaying finish; custom pipelines mis-wiring event ordering.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- [TRANSFORM-AGGREGATOR] Hash table already moved out
- Internal, AggregateBucketScatter only recv Partitioned…
- unreachable!()
- [TRANSFORM-AGGREGATOR] Invalid hash table state during…
- [TRANSFORM-AGGREGATOR] Invalid hash table state before spill
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/cbb5f53fad6a8d25.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/service/src/pipelines/processors/transforms/aggregator/transform_aggregate_partial.rs:247
impl AccumulatingTransform for TransformPartialAggregate {
const NAME: &'static str = "TransformPartialAggregate";
fn transform(&mut self, block: DataBlock) -> Result<Vec<DataBlock>> {
self.execute_one_block(block)?;
if self.settings.check_spill() {
self.spill_out()?;
}
Ok(vec![])
}
fn on_finish(&mut self, output: bool) -> Result<Vec<DataBlock>> {
Ok(match std::mem::take(&mut self.hash_table) {
HashTable::MovedOut => match !output {
true => vec![],
false => {
unreachable!("[TRANSFORM-AGGREGATOR] Hash table already moved out in finish")
}
},
HashTable::AggregateHashTable(hashtable) => {
let mut blocks = self.spillers.finish()?;
self.statistics.log_finish_statistics(&hashtable);
let payloads = hashtable
.payload
.into_bucket_payloads()
.map(|(bucket, payload)| AggregatePayload {
bucket: bucket as isize,
payload,
max_partition_count: 0,
})
.collect::<Vec<_>>();
blocks.push(DataBlock::empty_with_meta(
AggregateMeta::create_partitioned(View on GitHub (pinned to 288d84d76e)