{"record":{"id":"746e54e9b0c4e9a8","repo":"quickwit-oss/tantivy","slug":"key-length-mismatch","errorCode":null,"errorMessage":"Key length mismatch","messagePattern":"Key length mismatch","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/aggregation/bucket/composite/map.rs","lineNumber":30,"sourceCode":"#[derive(Clone, Debug)]\nstruct ArrayHeapMap<K: Ord, V, const S: usize> {\n    pub(crate) buckets: FxHashMap<[K; S], V>,\n    pub(crate) heap: BinaryHeap<[K; S]>,\n}\n\nimpl<K: Ord, V, const S: usize> Default for ArrayHeapMap<K, V, S> {\n    fn default() -> Self {\n        ArrayHeapMap {\n            buckets: FxHashMap::default(),\n            heap: BinaryHeap::default(),\n        }\n    }\n}\n\nimpl<K: Eq + Hash + Clone + Ord, V, const S: usize> ArrayHeapMap<K, V, S> {\n    /// Panics if the length of `key` is not S.\n    fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &[K], f: F) -> &mut V {\n        let key_array: &[K; S] = key.try_into().expect(\"Key length mismatch\");\n        self.buckets.entry(key_array.clone()).or_insert_with(|| {\n            self.heap.push(key_array.clone());\n            f()\n        })\n    }\n\n    /// Panics if the length of `key` is not S.\n    fn get_mut(&mut self, key: &[K]) -> Option<&mut V> {\n        let key_array: &[K; S] = key.try_into().expect(\"Key length mismatch\");\n        self.buckets.get_mut(key_array)\n    }\n\n    fn peek_highest(&self) -> Option<&[K]> {\n        self.heap.peek().map(|k_array| k_array.as_slice())\n    }\n\n    fn evict_highest(&mut self) {\n        if let Some(highest) = self.heap.pop() {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/quickwit-oss/tantivy/blob/b5d8deb80c26924e6b007a5b1a7630f35ca64de4/src/aggregation/bucket/composite/map.rs#L12-L48","documentation":"ArrayHeapMap is a fixed-size-key map where every key is [K; S]; get_or_insert_with converts the incoming &[K] slice to &[K; S] with try_into().expect(...). If the caller passes a key slice whose length differs from the const generic S, the conversion fails and the process panics with \"Key length mismatch\". The doc comment explicitly states this panic condition.","triggerScenarios":"Calling get_or_insert_with with a key slice of length != S — e.g. building composite bucket keys from a number of source fields different from the ArrayHeapMap's declared width S, or pushing an extra/missing key element.","commonSituations":"Composite aggregation over a variable number of fields while the heap map was sized for a fixed arity; field list built dynamically (empty field or extra field added) changing key length at runtime.","solutions":["Ensure the composite collector's key length always equals S: assert/derive S from the source field count and size the map with that constant.","Validate key.len() == S at the API boundary and return an error instead of reaching try_into.","Avoid hardcoded S; make it a computed const from the number of group-by fields so it can never diverge.","Add a debug_assert!(key.len() == S) in tests covering all field-count configurations."],"exampleFix":"// before\nlet key: &[K] = &dynamic_key; // length 3\nmap.get_or_insert_with(&key, default) // S == 2, panics\n// after\nassert_eq!(dynamic_key.len(), S, \"composite key arity must match map width\");\nmap.get_or_insert_with(&dynamic_key, default)","handlingStrategy":"validation","validationCode":"// Validate key length against map width before insert\nif key.len() != S {\n    return Err(TantivyError::InvalidArgument(format!(\n        \"composite key length {} != expected {}\", key.len(), S)));\n}\nmap.get_or_insert_with(key, default);","typeGuard":"fn key_len_ok<K>(key: &[K], s: usize) -> bool { key.len() == s }","tryCatchPattern":null,"preventionTips":["Derive S from the group-by field count, never hardcode it","Build keys through a single shared constructor","Assert key arity in debug builds and tests","Reject mismatched field lists at aggregation setup"],"tags":["rust","panic","aggregation","composite","slice-length"],"backgroundTag":"key-length-mismatch","analyzedSha":"b5d8deb80c26924e6b007a5b1a7630f35ca64de4","analyzedAt":"2026-09-05T13:20:51.521Z","contentChangedAt":"2026-09-05T13:20:51.521Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}