risingwavelabs/risingwave · error

Invalid order key column `{column}` HINT: Only plain column

Error message

Invalid order key column `{column}`
HINT: Only plain column names are supported in order_key

What it means

The first token of each order key item must match ORDER_KEY_COLUMN_RE, a pattern that accepts only plain SQL column identifiers. Quoted identifiers, qualified names like t.col, function calls, or other expression forms are rejected because the Iceberg sink order_key maps 1:1 onto table columns.

Source

Thrown at src/connector/src/sink/iceberg/create_table.rs:502

    for raw_item in expr.split(',') {
        let item = raw_item.trim();
        if item.is_empty() {
            bail!("Invalid order key: empty item in `{expr}`");
        }

        let tokens = item.split_whitespace().collect_vec();
        if tokens.is_empty() {
            bail!("Invalid order key item `{item}`");
        }
        if tokens.len() > 4 {
            bail!(
                "Invalid order key item `{item}`\nHINT: Supported format is `column [asc|desc] [nulls first|last]`"
            );
        }

        let column = tokens[0];
        if !ORDER_KEY_COLUMN_RE.is_match(column) {
            bail!(
                "Invalid order key column `{column}`\nHINT: Only plain column names are supported in order_key"
            );
        }
        if !seen_columns.insert(column.to_ascii_lowercase()) {
            bail!("Duplicate column `{column}` in order_key");
        }

        let mut direction = SortDirection::Ascending;
        let mut null_order = None;
        let mut idx = 1;
        while idx < tokens.len() {
            match tokens[idx].to_ascii_lowercase().as_str() {
                "asc" => {
                    direction = SortDirection::Ascending;
                    idx += 1;
                }
                "desc" => {
                    direction = SortDirection::Descending;

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Use the bare, unquoted column name exactly as declared (e.g. `id`, not `t.id` or `\"id\"`)
  2. Rename columns with special characters/spaces, or add clean alias columns
  3. Move any computed value into a real table column and reference that column in order_key
  4. Validate each item against the regex ^[A-Za-z_][A-Za-z0-9_]*$-style identifier before configuring

Example fix

// before
order_key = 't.event_time desc'
// after
order_key = 'event_time desc'
Defensive patterns

Strategy: validation

Validate before calling

let column_re = regex::Regex::new(r"^[A-Za-z_][A-Za-z0-9_]*$").unwrap();
for item in expr.split(',').map(|s| s.trim()) {
    let col = item.split_whitespace().next().unwrap_or("");
    if !column_re.is_match(col) {
        return Err(format!("order_key column `{col}` must be a plain identifier"));
    }
}

Type guard

fn is_plain_identifier(column: &str) -> bool {
    !column.is_empty()
        && column.chars().next().map_or(false, |c| c.is_ascii_alphabetic() || c == '_')
        && column.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
}

Prevention

When it happens

Trigger: order_key items such as `\"user id\"` (quoted), `t.id` (qualified), `count(*)`, `col + 1`, or identifiers starting with a digit/special char that fail the regex.

Common situations: Copying an ORDER BY expression from a query into order_key; qualifying column names out of habit; spaces inside a column name without knowing quoting is unsupported in this option.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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