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
- 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)`).
- Remove quotes and unsupported separators between parts.
- 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
- Use only documented forms: col, transform(col), transform(n,col), transform(n, col).
- Avoid bracket syntax (bucket[8]) and quoted identifiers in partition_by.
- Keep identifiers to \w+ characters (letters, digits, underscores).
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
- The `n` must be set with `bucket` and `truncate`
- `enable_config_load` can't be enabled in this environment
- invalid write_mode: {}, must be one of: {}, {}
- invalid compaction_type: {}, must be one of: {}, {}, {}, {}
- 'copy-on-write' mode is not supported for append-only iceber
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/01e9c2846087454d.
Report an issue: GitHub.