{"record":{"id":"5e11308b2ea1cd27","repo":"databendlabs/databend","slug":"transfer-target-payload-index-is-out-of-bounds","errorCode":null,"errorMessage":"transfer target payload index is out of bounds","messagePattern":"transfer target payload index is out of bounds","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/expression/src/aggregate/payload.rs","lineNumber":95,"sourceCode":"#[derive(Default)]\npub(super) struct PayloadTransferStateOffsets {\n    offsets: Vec<(usize, usize, usize)>,\n}\n\nimpl PayloadTransferStateOffsets {\n    fn record(&mut self, payload_index: usize, offsets: Vec<(usize, usize)>) {\n        self.offsets.extend(\n            offsets\n                .into_iter()\n                .map(|(page_index, offset)| (payload_index, page_index, offset)),\n        );\n    }\n\n    fn commit(self, payloads: &mut [Payload]) {\n        for (payload_index, page_index, offset) in self.offsets {\n            let payload = payloads\n                .get_mut(payload_index)\n                .expect(\"transfer target payload index is out of bounds\");\n\n            let page = payload\n                .pages\n                .get_mut(page_index)\n                .expect(\"transfer target page index is out of bounds\");\n            let next_state_offsets = page\n                .state_offsets\n                .checked_add(offset)\n                .expect(\"transfer target state offsets overflow\");\n            let initialized_states = page\n                .rows\n                .checked_mul(payload.aggrs.len())\n                .expect(\"transfer target initialized states overflow\");\n\n            assert!(\n                next_state_offsets <= initialized_states,\n                \"transfer target state offsets exceed initialized aggregate states\"\n            );","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/expression/src/aggregate/payload.rs#L77-L113","documentation":"During aggregation state transfer, commit() replays recorded (payload_index, page_index, offset) moves against the destination payloads slice. This panic fires when payloads.get_mut(payload_index) returns None, meaning the recorded target payload index no longer exists in the slice — an internal invariant violation in the aggregate payload arena.","triggerScenarios":"Calling commit_transferred_state_offsets when the offsets record a payload_index >= payloads.len(), typically after payloads were compacted/dropped or state transfer bookkeeping was computed against a different payload set.","commonSituations":"Distributed/window aggregate spilling or partial-transfer code paths where payload arenas are reallocated between move recording and commit; bugs after refactorings of the aggregate payload management.","solutions":["Verify that offsets are recorded and committed against the same, unchanged payloads collection — never drop/compact payloads between transfer and commit.","Assert/validate payload_index < payloads.len() at record time to fail earlier with a clearer message.","Update the transfer bookkeeping so it is re-derived after any payload arena mutation.","File a bug with the query shape; this is an internal invariant break, not user-fixable input."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"assert!(payload_index < payloads.len(), \"transfer offset references invalid payload {}\", payload_index);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never mutate (drop/compact) the payloads arena between recording and committing transfers","Validate indices at record time","Treat any hit as a bug report with the query plan attached"],"tags":["rust","panic","index-out-of-bounds","aggregation"],"backgroundTag":"index-out-of-bounds","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"}