risingwavelabs/risingwave · error

Invalid partition fields: {} HINT: Supported formats are col

Error message

Invalid partition fields: {}
HINT: Supported formats are column, transform(column), transform(n,column), transform(n, column)

What it means

`parse_partition_by_exprs` parses the sink's partition spec expression with a regex capturing `column`, `transform(column)`, `transform(n,column)`. If the whole expression does not match the pattern, it bails with `Invalid partition fields` plus a hint of supported formats.

Source

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

                 columns [{}].",
                idx,
                rw_field.name,
                arrow_field.name(),
                arrow_schema.fields().iter().map(|f| f.name()).join(", "),
            );
        }
    }

    Ok(())
}

pub fn parse_partition_by_exprs(
    expr: String,
) -> std::result::Result<Vec<(String, Transform)>, anyhow::Error> {
    // captures column, transform(column), transform(n,column), transform(n, column)
    let re = Regex::new(r"(?<transform>\w+)(\(((?<n>\d+)?(?:,|(,\s)))?(?<field>\w+)\))?").unwrap();
    if !re.is_match(&expr) {
        bail!(format!(
            "Invalid partition fields: {}\nHINT: Supported formats are column, transform(column), transform(n,column), transform(n, column)",
            expr
        ))
    }
    let caps = re.captures_iter(&expr);

    let mut partition_columns = vec![];

    for mat in caps {
        let (column, transform) = if mat.name("n").is_none() && mat.name("field").is_none() {
            (&mat["transform"], Transform::Identity)
        } else {
            let mut func = mat["transform"].to_owned();
            if func == "bucket" || func == "truncate" {
                let n = &mat
                    .name("n")
                    .ok_or_else(|| anyhow!("The `n` must be set with `bucket` and `truncate`"))?
                    .as_str();

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Rewrite the partition spec using the supported syntax: `col`, `transform(col)`, `transform(n,col)`, or `transform(n, col)` (e.g., `bucket(8, id)`, `truncate(3, name)`).
  2. Remove quotes and unsupported separators between parts.
  3. Validate each part matches `\w+` identifier rules (letters, digits, underscores only).

Example fix

// before
partition_by = 'bucket[8](id)'
// after
partition_by = 'bucket(8, id)'
Defensive patterns

Strategy: validation

Validate before calling

// validate partition_by syntax before passing it to the sink
const RE: &str = r"^(\w+(\(\d+\s*,\s*\w+\)|\(\w+\))?)(\s*,\s*\w+(\(\d+\s*,\s*\w+\)|\(\w+\))?)*$";
if !Regex::new(RE).unwrap().is_match(&partition_by) {
    return Err(format!("invalid partition_by: {partition_by}"));
}

Prevention

When it happens

Trigger: Called from `create_table_if_not_exists_impl` / `build_iceberg_engine_sink_options` when the `partition_by` sink option contains syntax the regex can't parse — e.g., commas separating multiple top-level parts in a way the regex rejects, quoted identifiers, spaces inside column names, or transform names with special characters.

Common situations: Users write `partition_by = 'bucket[8](id), truncate(3,name)'` style (bracket syntax instead of `bucket(8, id)`); quotes around identifiers; multi-expression strings with separators not supported; typos like extra parentheses or empty parts.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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