{"record":{"id":"3266bbcacbdb08f0","repo":"risingwavelabs/risingwave","slug":"duplicate-column-column-in-order-key","errorCode":null,"errorMessage":"Duplicate column `{column}` in order_key","messagePattern":"Duplicate column `(.+?)` in order_key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/connector/src/sink/iceberg/create_table.rs","lineNumber":507,"sourceCode":"\n        let tokens = item.split_whitespace().collect_vec();\n        if tokens.is_empty() {\n            bail!(\"Invalid order key item `{item}`\");\n        }\n        if tokens.len() > 4 {\n            bail!(\n                \"Invalid order key item `{item}`\\nHINT: Supported format is `column [asc|desc] [nulls first|last]`\"\n            );\n        }\n\n        let column = tokens[0];\n        if !ORDER_KEY_COLUMN_RE.is_match(column) {\n            bail!(\n                \"Invalid order key column `{column}`\\nHINT: Only plain column names are supported in order_key\"\n            );\n        }\n        if !seen_columns.insert(column.to_ascii_lowercase()) {\n            bail!(\"Duplicate column `{column}` in order_key\");\n        }\n\n        let mut direction = SortDirection::Ascending;\n        let mut null_order = None;\n        let mut idx = 1;\n        while idx < tokens.len() {\n            match tokens[idx].to_ascii_lowercase().as_str() {\n                \"asc\" => {\n                    direction = SortDirection::Ascending;\n                    idx += 1;\n                }\n                \"desc\" => {\n                    direction = SortDirection::Descending;\n                    idx += 1;\n                }\n                \"nulls\" => {\n                    let order = tokens.get(idx + 1).ok_or_else(|| {\n                        anyhow!(","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/connector/src/sink/iceberg/create_table.rs#L489-L525","documentation":"Each column may appear at most once in order_key. The parser tracks columns case-insensitively in a HashSet (seen_columns.insert with to_ascii_lowercase) and throws when a second item resolves to an already-seen column, since duplicate sort keys are ambiguous and invalid for an Iceberg sort spec.","triggerScenarios":"order_key strings like `id, ID`, `Name, name desc`, or literal repeats such as `created_at asc, created_at desc` reaching validate_order_key_columns.","commonSituations":"Accidental duplication when merging config fragments; case differences (`ID` vs `id`) masking a repeat to the eye; a generated list built from two sources that both include the same column.","solutions":["Deduplicate the column list (case-insensitively) before constructing order_key","If you intended different sort directions, keep only one item per column — the last duplicate does not override the first","Check for case-insensitive repeats like `id, ID`; identifiers are matched lowercased","If deduplicating programmatically, e.g. `cols.into_iter().collect::<HashSet<_>>()` on lowercased names, rebuild the string from the unique set"],"exampleFix":"// before\norder_key = 'user_id asc, user_id desc'\n// after\norder_key = 'user_id desc'","handlingStrategy":"validation","validationCode":"fn order_key_has_duplicates(expr: &str) -> bool {\n    let mut seen = std::collections::HashSet::new();\n    expr.split(',').any(|item| {\n        let col = item.trim().split_whitespace().next().unwrap_or(\"\").to_ascii_lowercase();\n        !seen.insert(col)\n    })\n}","typeGuard":"fn dedup_order_key(expr: &str) -> String {\n    let mut seen = std::collections::HashSet::new();\n    expr.split(',')\n        .filter(|item| seen.insert(item.trim().split_whitespace().next().unwrap_or(\"\").to_ascii_lowercase()))\n        .collect::<Vec<_>>()\n        .join(\",\")\n}","tryCatchPattern":null,"preventionTips":["Compare columns case-insensitively when deduplicating — `ID` and `id` collide","Deduplicate at the source of the column list, before join(\",\")","Keep exactly one sort direction per column; resolve conflicts before configuring","Add a dry-run parse (unit test) of any generated order_key string"],"tags":["validation","iceberg","duplicate-key","config"],"backgroundTag":"invalid-argument-format","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"}