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
- 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
- Verify build keys are serialized via the serializer path before finalize is invoked
- Check recent diffs to hash_join_build_state.rs for newly added key column types missing match coverage
- 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
- Extend insert_binary_key! match arms whenever a new key column type is added
- Run hash join tests covering every data type usable as a join key
- Include the offending variant in unreachable! messages for faster triage
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
- stage_prefix should never be called on external stage, must…
- HashJoinHashTable::NestedLoop(_) => unreachable!()
- HashJoinHashTable::NestedLoop(_) => unreachable!()
- _ => unreachable!()
- _ => unreachable!()
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)