risingwavelabs/risingwave · error

Invalid order key item `{item}` HINT: `NULLS` must be follow

Error message

Invalid order key item `{item}`
HINT: `NULLS` must be followed by `FIRST` or `LAST`

What it means

Thrown by `parse_order_key_exprs` when the token after `NULLS` is not `FIRST` or `LAST` (case-insensitive). The parser only accepts those two values for null ordering and rejects any other word with this message.

Source

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

            match tokens[idx].to_ascii_lowercase().as_str() {
                "asc" => {
                    direction = SortDirection::Ascending;
                    idx += 1;
                }
                "desc" => {
                    direction = SortDirection::Descending;
                    idx += 1;
                }
                "nulls" => {
                    let order = tokens.get(idx + 1).ok_or_else(|| {
                        anyhow!(
                            "Invalid order key item `{item}`: `NULLS` must be followed by `FIRST` or `LAST`"
                        )
                    })?;
                    null_order = Some(match order.to_ascii_lowercase().as_str() {
                        "first" => NullOrder::First,
                        "last" => NullOrder::Last,
                        _ => bail!(
                            "Invalid order key item `{item}`\nHINT: `NULLS` must be followed by `FIRST` or `LAST`"
                        ),
                    });
                    idx += 2;
                }
                token => {
                    bail!(
                        "Invalid order key token `{token}` in `{item}`\nHINT: Supported format is `column [asc|desc] [nulls first|last]`"
                    );
                }
            }
        }

        order_keys.push(IcebergOrderKeyField {
            column: column.to_owned(),
            direction,
            null_order: null_order
                .unwrap_or_else(|| IcebergOrderKeyField::default_null_order(direction)),

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Replace the token after `NULLS` with exactly `FIRST` or `LAST` (any case)
  2. Remove the `NULLS ...` clause entirely to use the default null order for the direction
  3. Check the item for stray characters or split words, e.g. `nulls firstt`

Example fix

// before
order_key = 'ts desc nulls top'
// after
order_key = 'ts desc nulls last'
Defensive patterns

Strategy: validation

Validate before calling

fn valid_null_order(item: &str) -> bool {
    let toks: Vec<&str> = item.to_ascii_lowercase().split_whitespace().collect();
    !toks.windows(2).any(|w| w[0] == "nulls" && !matches!(w[1], "first" | "last"))
}
assert!(order_key.split(',').all(|i| valid_null_order(i.trim())));

Try / catch

match parse_order_key_exprs(item) {
    Ok(keys) => keys,
    Err(e) if e.to_string().contains("HINT: `NULLS`") => {
        eprintln!("use FIRST or LAST after NULLS: {e}");
        Default::default()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Passing an order key item like `col asc nulls ignore` or `col nulls firts` (misspelled) in the Iceberg sink `order_key` option — `NULLS` is present and followed by a token, but the token is not `FIRST`/`LAST`.

Common situations: Typos such as `nulls NLast`, using other SQL dialects' null-ordering words, or confusing `NULLS FIRST` with `NULLSFIRST`-style compact syntax in the config.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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