databendlabs/databend · error

_ => unreachable!()

Error message

_ => unreachable!()

What it means

The probe transform's process() matches on its Step state machine; the catch-all panics because a step invalid for the synchronous probe phase reached process(). Like the build transform's equivalents, this asserts pipeline scheduling never routes unhandled steps here.

Solutions

  1. Add or correct the match arm for the offending step in process()
  2. Embed the step value in the panic message to ease debugging
  3. Audit the probe transform's state transitions so each step is consumed in exactly one phase
  4. Reproduce with concurrent probe/final-scan workloads and check scheduler logs

Example fix

// before
_ => unreachable!(),
// after
other => unreachable!("TransformHashJoinProbe::process got unexpected step: {:?}", other),
Defensive patterns

Strategy: validation

Validate before calling

// Verify the step belongs to the synchronous probe phase
if !matches!(self.step, Step::Consume | Step::Sync(_)) {
    return Err(ErrorCode::Internal("probe process() called with invalid step"));
}

Type guard

fn is_probe_sync_step(s: &Step) -> bool {
    !matches!(s, Step::Async(_))
}

Prevention

When it happens

Trigger: The step field contains a variant not handled by process() (e.g. an async-only step such as WaitBuild, or a finish step routed incorrectly) due to a transition or scheduling bug.

Common situations: After adding new Step/AsyncStep variants; races between probe final scan and build wait; regressions from refactoring the probe transform's event loop.

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

Appendix: source

Thrown at src/query/service/src/pipelines/processors/transforms/hash_join/transform_hash_join_probe.rs:382

                            self.fill_rows(task)?;
                            return Ok(());
                        }
                    }
                    FinalScanType::MergeInto => {
                        if let Some(item) = self
                            .join_probe_state
                            .final_merge_into_partial_unmodified_scan_task()
                        {
                            self.final_merge_into_partial_unmodified_scan(item)?;
                            return Ok(());
                        }
                    }
                }
                // No more task, final scan finished.
                self.is_final_scan_finished = true;
                Ok(())
            }
            _ => unreachable!(),
        }
    }

    #[async_backtrace::framed]
    async fn async_process(&mut self) -> Result<()> {
        match self.step {
            Step::Async(AsyncStep::WaitBuild) => {
                self.hash_table_type = self
                    .join_probe_state
                    .hash_join_state
                    .wait_build_notify()
                    .await?;
                self.is_spill_happened = self
                    .join_probe_state
                    .hash_join_state
                    .is_spill_happened
                    .load(Ordering::Acquire);
                self.is_build_finished = true;

View on GitHub (pinned to 288d84d76e)