{"record":{"id":"19b37117105cd828","repo":"risingwavelabs/risingwave","slug":"distribution-key-must-be-a-subset-of-primary","errorCode":null,"errorMessage":"distribution key {:?} must be a subset of primary key {:?}","messagePattern":"distribution key (.+?) must be a subset of primary key (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/common/src/catalog/internal_table.rs","lineNumber":66,"sourceCode":"\npub fn is_source_backfill_table(table_name: &str) -> bool {\n    let parts: Vec<&str> = table_name.split('_').collect();\n    let parts_len = parts.len();\n    parts_len >= 2 && parts[parts_len - 2] == \"sourcebackfill\"\n}\n\npub fn get_dist_key_in_pk_indices<I: Eq + Copy + Debug, O: TryFrom<usize>>(\n    dist_key_indices: &[I],\n    pk_indices: &[I],\n) -> anyhow::Result<Vec<O>> {\n    dist_key_indices\n        .iter()\n        .map(|&di| {\n            pk_indices\n                .iter()\n                .position(|&pi| di == pi)\n                .ok_or_else(|| {\n                    anyhow!(\n                        \"distribution key {:?} must be a subset of primary key {:?}\",\n                        dist_key_indices,\n                        pk_indices\n                    )\n                })\n                .map(|idx| match O::try_from(idx) {\n                    Ok(idx) => idx,\n                    Err(_) => unreachable!(\"failed to cast {} to {}\", idx, type_name::<O>()),\n                })\n        })\n        .try_collect()\n}\n\n/// Get distribution key start index in pk, and return None if `dist_key_in_pk_indices` is not empty\n/// or continuous.\n/// Note that `dist_key_in_pk_indices` may be shuffled, the start index should be the\n/// minimum value.\npub fn get_dist_key_start_index_in_pk(dist_key_in_pk_indices: &[usize]) -> Option<usize> {","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/common/src/catalog/internal_table.rs#L48-L84","documentation":"`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.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"// before\nlet catalog = TableCatalog::new(pk_indices, dist_key_indices /* includes col not in pk */...);\n// after: assert subset before constructing\ndebug_assert!(dist_key_indices.iter().all(|d| pk_indices.contains(d)),\n    \"distribution key must be a subset of primary key\");\nlet catalog = TableCatalog::new(pk_indices, dist_key_indices, ...);","handlingStrategy":"validation","validationCode":"fn dist_key_in_pk(dist: &[usize], pk: &[usize]) -> bool {\n    dist.iter().all(|d| pk.contains(d))\n}","typeGuard":null,"tryCatchPattern":"let dist_in_pk = catalog.get_dist_key_in_pk_indices::<'_, usize>()\n    .map_err(|e| anyhow!(\"table {} has invalid dist key: {}\", catalog.name, e))?;","preventionTips":["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"],"tags":["rust","catalog","distribution-key","primary-key"],"backgroundTag":"invalid-argument-value","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}