databendlabs/databend · error
_ => unreachable!()
Error message
_ => unreachable!()
What it means
The build transform's process() matches on its Step enum to drive the pipeline state machine. The catch-all arm panics, meaning a Step variant (e.g. a synchronous step not expected in process, or a wrongly-set step) reached the synchronous processing path. This is an internal state-machine invariant: only specific steps are valid for synchronous processing.
Solutions
- Add a match arm for the unexpected Step variant in process(), or route it to the correct handler
- Log the actual step value in the panic message to accelerate diagnosis
- Audit all Step/AsyncStep variants and confirm each is handled in exactly the right phase
- Check recent changes to the build transform state machine
Example fix
// before
_ => unreachable!(),
// after
other => unreachable!("TransformHashJoinBuild::process got unexpected step: {:?}", other), Defensive patterns
Strategy: validation
Validate before calling
// Assert the step is valid for synchronous processing before calling process()
match &self.step {
Step::NeedInput | Step::Consume => {},
other => return Err(ErrorCode::Internal(format!("invalid step for process(): {:?}", other))),
} Type guard
fn sync_step(s: &Step) -> bool {
matches!(s, Step::NeedInput | Step::Consume | Step::Sync(_))
} Prevention
- Include the step value in every unreachable! in pipeline state machines
- Add new Step variants' handling in the same commit that introduces them
- Write state-machine tests driving process()/async_process() through all steps
When it happens
Trigger: The transform's step field holds a Step value that process() does not explicitly handle (e.g. an async-only step, or a stale step left after a state transition bug).
Common situations: Regressions after adding new AsyncStep/Step variants without updating process(); pipeline scheduling anomalies where event()/process()/async_process() interleave unexpectedly.
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
- _ => unreachable!()
- internal error: entered unreachable code
- _ => unreachable!()
- HashJoinHashTable::NestedLoop(_) => unreachable!()
- HashJoinHashTable::NestedLoop(_) => unreachable!()
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/0bde365fec5950eb.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/service/src/pipelines/processors/transforms/hash_join/transform_hash_join_build.rs:283
if let Some(builder) = self.runtime_filter_builder.as_mut() {
builder.add_block(data_block)?;
}
}
}
}
self.data_blocks.clear();
self.is_collect_finished = true;
self.build_state.collect_done()
}
Step::Sync(SyncStep::Finalize) => {
if let Some(task) = self.build_state.finalize_task() {
self.build_state.finalize(task)
} else {
self.is_finalize_finished = true;
self.build_state.finalize_done(self.hash_table_type)
}
}
_ => unreachable!(),
}
}
#[async_backtrace::framed]
async fn async_process(&mut self) -> Result<()> {
match &self.step {
Step::Async(AsyncStep::CheckSpillHappen) => {
self.build_state.barrier.wait().await;
self.is_spill_happen_checked = true;
self.is_spill_happened = self
.build_state
.hash_join_state
.is_spill_happened
.load(Ordering::Acquire);
}
Step::Async(AsyncStep::WaitCollect) => {
if let Some(builder) = self.runtime_filter_builder.take() {
let spill = selfView on GitHub (pinned to 288d84d76e)