databendlabs/databend · error

_ => unreachable!()

Error message

_ => unreachable!()

What it means

The insert_binary_key! macro in hash_join_build_state.rs assumes that when finalizing a build chunk, the keys state is always a String, Binary, Variant, or Bitmap column. Any other Column variant reaching this match means the caller passed serialized/binary key columns inconsistent with what this macro handles, so the code deliberately panics with unreachable!() instead of returning an error. This is an internal invariant assertion, not a user-facing error.

Solutions

  1. Inspect the keys_state column variant at the panic and add a matching arm in insert_binary_key! that computes total space size for the new type
  2. Verify build keys are serialized via the serializer path before finalize is invoked
  3. Check recent diffs to hash_join_build_state.rs for newly added key column types missing match coverage
  4. File a bug with the query plan and key types if hit on an unmodified build

Example fix

// before
_ => unreachable!(),
// after
KeysState::Column(Column::Number(NumberColumn::UInt64(col))) => col.len() * 8,
_ => unreachable!("unexpected keys state for binary key insert"),
Defensive patterns

Strategy: validation

Validate before calling

// Before calling finalize, confirm keys_state holds a serializable column type
fn is_binary_key_state(keys_state: &KeysState) -> bool {
    matches!(keys_state, KeysState::Column(Column::String(_)
        | Column::Binary(_) | Column::Variant(_) | Column::Bitmap(_)))
}
assert!(is_binary_key_state(&keys_state), "finalize called with non-binary keys_state");

Type guard

fn is_binary_key_state(keys_state: &KeysState) -> bool {
    matches!(keys_state, KeysState::Column(Column::String(_)
        | Column::Binary(_) | Column::Variant(_) | Column::Bitmap(_)))
}

Prevention

When it happens

Trigger: Calling finalize on a build state whose keys_state holds a non-serialized column type (e.g. Number, Boolean, Nullable variant) while the UniqueSerializer/UniqueSingleBinary insert path expects binary-serialized keys. Usually caused by a code change introducing a new key column type without extending the macro's match arms.

Common situations: Developers adding a new data type to hash join keys; running a modified/patched build where key serialization logic was altered; fuzzing or integration tests exercising unusual key types against a binary-key hash table.

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


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/ee76cd06e13e8971. Report an issue: GitHub.

Appendix: source

Thrown at src/query/service/src/pipelines/processors/transforms/hash_join/hash_join_build_state.rs:516

                local_raw_entry_spaces.push(local_space);
                if is_interrupted {
                    return Err(ErrorCode::aborting());
                }
            }};
        }

        macro_rules! insert_binary_key {
            ($table: expr, $method: expr, $chunk: expr, $build_keys: expr, $valids: expr, $chunk_index: expr, $entry_size: expr, $local_raw_entry_spaces: expr, ) => {{
                let keys_state = $method.build_keys_state($build_keys, $chunk.num_rows())?;
                let build_keys_iter = $method.build_keys_iter(&keys_state)?;

                let space_size = match &keys_state {
                    // safe to unwrap(): offset.len() >= 1.
                    KeysState::Column(Column::String(col)) => col.total_bytes_len(),
                    KeysState::Column(
                        Column::Binary(col) | Column::Variant(col) | Column::Bitmap(col),
                    ) => col.data().len(),
                    _ => unreachable!(),
                };
                let valid_num = match &$valids {
                    Some(valids) => valids.len() - valids.null_count(),
                    None => $chunk.num_rows(),
                };
                let mut entry_local_space: Vec<u8> = Vec::with_capacity(valid_num * entry_size);
                let mut string_local_space: Vec<u8> = Vec::with_capacity(space_size as usize);
                let mut raw_entry_ptr = unsafe {
                    std::mem::transmute::<*mut u8, *mut StringRawEntry>(
                        entry_local_space.as_mut_ptr(),
                    )
                };
                let mut string_local_space_ptr = string_local_space.as_mut_ptr();

                match $valids {
                    Some(valids) => {
                        for (row_index, (key, valid)) in
                            build_keys_iter.zip(valids.iter()).enumerate()

View on GitHub (pinned to 288d84d76e)