databendlabs/databend · error

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

Error message

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

What it means

InnerHashJoin::probe_block panics when the probe side encounters a NestedLoop hash table variant, which by design never participates in hash probing. The match otherwise returns AbortedQuery for an uninitialized (Null) table, so this arm is a pure internal invariant check.

Solutions

  1. Check join-type/equi-condition detection upstream so nested-loop joins never build InnerHashJoin probe processors
  2. Ensure the processor used matches the HashJoinHashTable variant chosen at build time
  3. Convert the arm to ErrorCode::Internal with context to make future hits diagnosable instead of a bare panic
  4. Run new_hash_join inner-join integration tests after executor-routing changes

Example fix

// before
HashJoinHashTable::NestedLoop(_) => unreachable!(),
// after
HashJoinHashTable::NestedLoop(_) => Err(ErrorCode::Internal(
    "NestedLoop table cannot be probed by inner hash join")),
Defensive patterns

Strategy: validation

Validate before calling

debug_assert!(!matches!(*self.basic_state.state.hash_table.deref(), HashJoinHashTable::NestedLoop(_)), "NestedLoop table in inner join probe path");

Type guard

fn probeable(t: &HashJoinHashTable) -> bool {
    !matches!(t, HashJoinHashTable::NestedLoop(_))
}

Prevention

When it happens

Trigger: A nested-loop join (cross or non-equi) is executed through the memory hash-join probe path, i.e. probe_block runs while state.hash_table holds HashJoinHashTable::NestedLoop.

Common situations: Incorrect executor selection for cross joins, refactor where inner-join probe processors are attached to a nested-loop pipeline, or tests wiring a NestedLoop table into InnerHashJoin.

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/02c2e09d811f8f57. Report an issue: GitHub.

Appendix: source

Thrown at src/query/service/src/pipelines/processors/transforms/new_hash_join/memory/inner_join.rs:153

        let probe_block = data.project(&self.desc.probe_projection);

        let joined_stream = with_join_hash_method!(|T| match self.basic_state.hash_table.deref() {
            HashJoinHashTable::T(table) => {
                let probe_hash_statistics = &mut self.performance_context.probe_hash_statistics;
                probe_hash_statistics.clear(probe_block.num_rows());

                let probe_data = ProbeData::new(keys, valids, probe_hash_statistics);
                let probe_keys_stream = table.probe_matched(probe_data)?;

                InnerHashJoinStream::create(
                    probe_block,
                    self.basic_state.clone(),
                    probe_keys_stream,
                    self.desc.clone(),
                    &mut self.performance_context.probe_result,
                )
            }
            HashJoinHashTable::NestedLoop(_) => unreachable!(),
            HashJoinHashTable::Null => {
                return Err(ErrorCode::AbortedQuery(
                    "Aborted query, because the hash table is uninitialized.",
                ));
            }
        });

        match &mut self.performance_context.filter_executor {
            None => Ok(joined_stream),
            Some(filter_executor) => Ok(InnerHashJoinFilterStream::create(
                joined_stream,
                filter_executor,
            )),
        }
    }
}

struct InnerHashJoinStream<'a> {

View on GitHub (pinned to 288d84d76e)