quickwit-oss/tantivy · error

non-zero packed bits fit in u64

Error message

non-zero packed bits fit in u64

What it means

This is a Rust panic from an `expect` on `u64::checked_shl` inside `shift_packed_bits` in multi-terms aggregation. The function shifts a field's packed bits left by a computed shift amount, and the panic fires when `shift >= 64` (or bits would overflow), meaning the combined per-field bit offsets of the terms aggregation exceed the 64 bits available in a single packed key. The library assumes the sum of all field max_offsets stays within 64 bits; a mis-computed or corrupt pack layout violates that invariant.

Source

Thrown at src/aggregation/bucket/multi_terms/mod.rs:983

        packs.push(FieldPack {
            shift,
            mask,
            min_value,
            max_offset,
        });
        shift += width;
    }
    packs.reverse();
    Some(packs)
}

#[inline]
fn shift_packed_bits(bits: u64, shift: u32) -> u64 {
    if bits == 0 {
        0
    } else {
        bits.checked_shl(shift)
            .expect("non-zero packed bits fit in u64")
    }
}

fn compute_max_packed(packs: &[FieldPack]) -> u64 {
    packs.iter().fold(0u64, |packed, field| {
        packed | shift_packed_bits(field.max_offset, field.shift)
    })
}

#[derive(Clone, Debug)]
struct PackedU64KeyPacking {
    packs: Vec<FieldPack>,
}

/// Selects the key packing and bucket storage, then boxes the concrete collector.
fn build_multi_terms_collector<BucketSlot: BucketIdSlot>(
    req: &mut AggregationsSegmentCtx,
    node: &AggRefNode,

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. Reduce the number of fields in the multi_terms aggregation so the combined bit width fits in 64 bits.
  2. Check term/ordinal cardinality of the involved fields; split the aggregation or use a composite aggregation instead.
  3. If you maintain the code, return a Result from shift_packed_bits and surface a user-facing error instead of expecting.
  4. Reindex the field if a corrupt or oversized ordinal layout is suspected.

Example fix

// before
bits.checked_shl(shift).expect("non-zero packed bits fit in u64")
// after
bits.checked_shl(shift)
    .ok_or_else(|| crate::AggregationError::Internal("packed bits overflow u64".to_string()))?
Defensive patterns

Strategy: validation

Validate before calling

// Before issuing a multi_terms agg, bound the combined ordinal bit width of the fields.
fn packed_bits_fit_in_u64(field_max_offsets: &[u64]) -> bool {
    field_max_offsets.iter().map(|o| 64 - o.leading_zeros()).sum::<u32>() <= 64
}
if !packed_bits_fit_in_u64(&offsets) {
    // fall back to a composite aggregation instead of multi_terms
}

Prevention

When it happens

Trigger: Calling a multi_terms aggregation whose per-field packed bit layout (`field.max_offset` + `field.shift`) exceeds 64 total bits, e.g. very high-cardinality or wide ordinal fields combined in one multi_terms agg, so `checked_shl(shift)` returns None and the expect panics.

Common situations: Multi-terms aggregation over many fields or fields with large term dictionaries where the sum of bit widths of all sub-fields overflows u64; index segments with unexpectedly large ordinals after mapping or index-version changes.

Related errors


AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05). Data as JSON: /api/errors/c7e6307caff1ea84. Report an issue: GitHub.