risingwavelabs/risingwave · error
dist_key must in order_key
Error message
dist_key must in order_key
What it means
gen_batch_lookup_join computes the position of each distribution key column within the lookup table's order key and expect()s it to be found. If a distribution key column is not part of the primary-key/order columns, the invariant `dist_key must in order_key` is violated and it panics.
Solutions
- Ensure the lookup table's distribution key is a prefix/subset of its primary key (order key) columns
- Re-create the table with a PRIMARY KEY that matches its distribution
- Skip lookup-join conversion when the invariant does not hold and use a normal hash join
- Validate table.distribution_key ⊆ order_column_indices before calling
Example fix
// before
let pos = table.order_column_indices().position(|x| x == d).expect("dist_key must in order_key");
// after
let pos = match table.order_column_indices().position(|x| x == d) {
Some(p) => p,
None => return Err(anyhow!("distribution key {:?} not in order key of lookup table", d)),
}; Defensive patterns
Strategy: validation
Validate before calling
fn dist_key_in_order_key(table: &TableCatalog) -> bool { table.distribution_key.iter().all(|d| table.order_column_indices().any(|o| o == *d)) } Prevention
- Define tables with PRIMARY KEY aligned to distribution key
- Validate dist_key ⊆ order_column_indices before lookup join conversion
- Add precondition assertions with descriptive errors instead of expect
When it happens
Trigger: Calling gen_batch_lookup_join (public) with a lookup table whose distribution key columns are not a subset of its order column indices.
Common situations: Lookup join against a table with a custom/non-default distribution or after schema changes where the distribution no longer aligns with the primary key; also hit by API users constructing lookup joins programmatically.
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
- index scan failed to batch
- call predicate_pushdown of the PlanRef instead of calling…
- call prune_col of the PlanRef instead of calling directly…
- collection.name.field
- ` ` column not found in backfill table
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/529580509a25844a.
Report an issue: GitHub.
Appendix: source
Thrown at src/frontend/src/optimizer/plan_node/logical_join.rs:408
| JoinType::AsofInner
| JoinType::AsofLeftOuter => {}
_ => return Ok(None),
};
let table = logical_scan.table();
let output_column_ids = logical_scan.output_column_ids();
// Verify that the right join key columns are the the prefix of the primary key and
// also contain the distribution key.
let order_col_ids = table.order_column_ids();
let dist_key = table.distribution_key.clone();
// The at least prefix of order key that contains distribution key.
let mut dist_key_in_order_key_pos = vec![];
for d in dist_key {
let pos = table
.order_column_indices()
.position(|x| x == d)
.expect("dist_key must in order_key");
dist_key_in_order_key_pos.push(pos);
}
// The shortest prefix of order key that contains distribution key.
//
// If the lookup table has a singleton distribution (i.e. an empty distribution key),
// any non-empty prefix of the order key can be used for the lookup, so we require a
// prefix of length at least 1.
let shortest_prefix_len = dist_key_in_order_key_pos
.iter()
.max()
.map_or(1, |pos| pos + 1);
// Reorder the join equal predicate to match the order key.
let reorder_idx =
Self::lookup_prefix_reorder_idx(&predicate, &output_column_ids, &order_col_ids);
if reorder_idx.len() < shortest_prefix_len {
return Ok(None);
}View on GitHub (pinned to 6469eb736d)