databendlabs/databend · error

HashJoinHashTable::NestedLoop(_) => unreachable!()

Error message

HashJoinHashTable::NestedLoop(_) => unreachable!()

What it means

During the probe phase (next_probe), the code matches on the join's hash table type. A NestedLoop join has no hash table to probe, so hitting that arm means the executor is probing a join that was planned as a nested loop — an internal state/dispatch contradiction. The code panics rather than returning an error because this should be impossible.

Solutions

  1. Ensure nested-loop joins take a separate execution path and never instantiate the hash probe transform
  2. Return a proper ErrorCode (e.g. Unimplemented) for NestedLoop in the probe dispatch
  3. Check EXPLAIN of the failing query for strategy selection inconsistencies
  4. Patch or upgrade the join planner/executor integration

Example fix

// before
HashJoinHashTable::NestedLoop(_) => unreachable!(),
// after
HashJoinHashTable::NestedLoop(_) => Err(ErrorCode::Unimplemented(
    "Nested loop join should not be probed via hash table",
)),
Defensive patterns

Strategy: validation

Validate before calling

// Guard before probing
if matches!(table_type, HashJoinHashTable::NestedLoop(_)) {
    return Err(ErrorCode::Unimplemented("cannot probe a nested loop join"));
}

Type guard

fn probeable(t: &HashJoinHashTable) -> bool {
    matches!(t, HashJoinHashTable::Serializer(_) | HashJoinHashTable::SingleBinary(_) | HashJoinHashTable::UniqueSerializer(_) | HashJoinHashTable::UniqueSingleBinary(_))
}

Prevention

When it happens

Trigger: next_probe is invoked on a probe state whose hash table is NestedLoop(_), i.e. the pipeline built a nested-loop join but routed data through the hash-probe path, typically due to plan/executor mismatch or missing NestedLoop handling in the probe transform.

Common situations: Inequality or cross joins misrouted into hash join execution; custom join strategies; regressions after refactoring HashJoinHashTable dispatch.

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/1a341cbba4442da7. Report an issue: GitHub.

Appendix: source

Thrown at src/query/service/src/pipelines/processors/transforms/hash_join/hash_join_probe_state.rs:169

        match self.hash_join_state.hash_join_desc.join_type {
            JoinType::Cross => self.cross_join(input, probe_state),
            _ => self.probe_join(input, probe_state),
        }
    }

    pub fn next_probe(&self, probe_state: &mut ProbeState) -> Result<Vec<DataBlock>> {
        let process_state = probe_state.process_state.as_ref().unwrap();
        let hash_table = unsafe { &*self.hash_join_state.hash_table.get() };
        with_join_hash_method!(|T| match hash_table {
            HashJoinHashTable::T(table) => {
                // Build `keys` and get the hashes of `keys`.
                let keys = table
                    .hash_method
                    .build_keys_accessor(process_state.keys_state.clone())?;
                // Continue to probe hash table and process data blocks.
                self.result_blocks(probe_state, keys, &table.hash_table)
            }
            HashJoinHashTable::NestedLoop(_) => unreachable!(),
            HashJoinHashTable::Null => Err(ErrorCode::AbortedQuery(
                "Aborted query, because the hash table is uninitialized.",
            )),
        })
    }

    pub fn probe_join(
        &self,
        mut input: DataBlock,
        probe_state: &mut ProbeState,
    ) -> Result<Vec<DataBlock>> {
        let input_num_rows = input.num_rows();
        let mut _nullable_data_block = None;
        let evaluator = if matches!(
            self.hash_join_state.hash_join_desc.join_type,
            JoinType::Right | JoinType::RightAny | JoinType::RightSingle | JoinType::Full
        ) {
            let nullable_columns = input

View on GitHub (pinned to 288d84d76e)