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

  1. Ensure every distribution key column is part of the primary key when defining the table.
  2. Fix the table definition (DDL or catalog construction code) so `distribution_key ⊆ pk_indices`.
  3. If this arises from `try_to_protobuf`, inspect the catalog object being serialized for corrupted dist-key metadata.
  4. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/19b37117105cd828. Report an issue: GitHub.