risingwavelabs/risingwave · error
distribution key {:?} must be a subset of primary key {:?}
Error message
distribution key {:?} must be a subset of primary key {:?} What it means
`get_dist_key_in_pk_indices` maps each distribution-key index to its position within the primary-key indices. If any distribution key index is not present in `pk_indices`, the mapping is impossible — a distribution key must be a subset of the primary key for internal tables — so this error is returned.
Source
Thrown at src/common/src/catalog/internal_table.rs:66
pub fn is_source_backfill_table(table_name: &str) -> bool {
let parts: Vec<&str> = table_name.split('_').collect();
let parts_len = parts.len();
parts_len >= 2 && parts[parts_len - 2] == "sourcebackfill"
}
pub fn get_dist_key_in_pk_indices<I: Eq + Copy + Debug, O: TryFrom<usize>>(
dist_key_indices: &[I],
pk_indices: &[I],
) -> anyhow::Result<Vec<O>> {
dist_key_indices
.iter()
.map(|&di| {
pk_indices
.iter()
.position(|&pi| di == pi)
.ok_or_else(|| {
anyhow!(
"distribution key {:?} must be a subset of primary key {:?}",
dist_key_indices,
pk_indices
)
})
.map(|idx| match O::try_from(idx) {
Ok(idx) => idx,
Err(_) => unreachable!("failed to cast {} to {}", idx, type_name::<O>()),
})
})
.try_collect()
}
/// Get distribution key start index in pk, and return None if `dist_key_in_pk_indices` is not empty
/// or continuous.
/// Note that `dist_key_in_pk_indices` may be shuffled, the start index should be the
/// minimum value.
pub fn get_dist_key_start_index_in_pk(dist_key_in_pk_indices: &[usize]) -> Option<usize> {View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure every distribution key column is part of the primary key when defining the table.
- Fix the table definition (DDL or catalog construction code) so `distribution_key ⊆ pk_indices`.
- If this arises from `try_to_protobuf`, inspect the catalog object being serialized for corrupted dist-key metadata.
- Check migration/tooling code that rewrites pk_indices without updating distribution_key.
Example fix
// before
let catalog = TableCatalog::new(pk_indices, dist_key_indices /* includes col not in pk */...);
// after: assert subset before constructing
debug_assert!(dist_key_indices.iter().all(|d| pk_indices.contains(d)),
"distribution key must be a subset of primary key");
let catalog = TableCatalog::new(pk_indices, dist_key_indices, ...); Defensive patterns
Strategy: validation
Validate before calling
fn dist_key_in_pk(dist: &[usize], pk: &[usize]) -> bool {
dist.iter().all(|d| pk.contains(d))
} Try / catch
let dist_in_pk = catalog.get_dist_key_in_pk_indices::<'_, usize>()
.map_err(|e| anyhow!("table {} has invalid dist key: {}", catalog.name, e))?; Prevention
- Enforce distribution_key ⊆ pk_indices when building TableCatalog
- Validate catalog objects in tests/migrations before persistence
- When rewriting PK columns, update distribution_key in lockstep
When it happens
Trigger: Calling `TableCatalog::get_dist_key_in_pk_indices` (directly or via `try_to_protobuf`/`new`) with a table whose `distribution_key` contains an index that does not appear in `pk_indices`.
Common situations: Constructing an internal table catalog programmatically with mismatched dist key and PK; schema definition bugs when creating materialized views/internal tables; hand-edited catalog metadata in tests or migrations.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Primary key not defined for upsert doris sink (please define
- no value find in sink schema, index is {:?}
- please set the separator in the with option, when there are
- {e}
- failed to create iceberg table
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/19b37117105cd828.
Report an issue: GitHub.