quickwit-oss/tantivy · error
Key length mismatch
Error message
Key length mismatch
What it means
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.
Source
Thrown at src/aggregation/bucket/composite/map.rs:30
#[derive(Clone, Debug)]
struct ArrayHeapMap<K: Ord, V, const S: usize> {
pub(crate) buckets: FxHashMap<[K; S], V>,
pub(crate) heap: BinaryHeap<[K; S]>,
}
impl<K: Ord, V, const S: usize> Default for ArrayHeapMap<K, V, S> {
fn default() -> Self {
ArrayHeapMap {
buckets: FxHashMap::default(),
heap: BinaryHeap::default(),
}
}
}
impl<K: Eq + Hash + Clone + Ord, V, const S: usize> ArrayHeapMap<K, V, S> {
/// Panics if the length of `key` is not S.
fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &[K], f: F) -> &mut V {
let key_array: &[K; S] = key.try_into().expect("Key length mismatch");
self.buckets.entry(key_array.clone()).or_insert_with(|| {
self.heap.push(key_array.clone());
f()
})
}
/// Panics if the length of `key` is not S.
fn get_mut(&mut self, key: &[K]) -> Option<&mut V> {
let key_array: &[K; S] = key.try_into().expect("Key length mismatch");
self.buckets.get_mut(key_array)
}
fn peek_highest(&self) -> Option<&[K]> {
self.heap.peek().map(|k_array| k_array.as_slice())
}
fn evict_highest(&mut self) {
if let Some(highest) = self.heap.pop() {View on GitHub (pinned to b5d8deb80c)
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.
Example fix
// before let key: &[K] = &dynamic_key; // length 3 map.get_or_insert_with(&key, default) // S == 2, panics // after assert_eq!(dynamic_key.len(), S, "composite key arity must match map width"); map.get_or_insert_with(&dynamic_key, default)
Defensive patterns
Strategy: validation
Validate before calling
// Validate key length against map width before insert
if key.len() != S {
return Err(TantivyError::InvalidArgument(format!(
"composite key length {} != expected {}", key.len(), S)));
}
map.get_or_insert_with(key, default); Type guard
fn key_len_ok<K>(key: &[K], s: usize) -> bool { key.len() == s } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- dictionary missing for str accessor
- could not convert to String
- unsupported
- unexpected type {:?}. This should not happen
- interval not precomputed for date histogram source
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/746e54e9b0c4e9a8.
Report an issue: GitHub.