dbt-labs/dbt-core · error
Table.rename: row_names must be a map or an array
Error message
Table.rename: row_names must be a map or an array
What it means
Table.rename was called with a row_names argument that is neither a map (old row-name -> new row-name) nor an array of new row names. Like the column_names case, the value is probed for iteration and this error is thrown if it cannot be iterated.
Source
Thrown at crates/dbt-agate/src/table.rs:747
renamed.append_value(old_name);
}
} else {
renamed.append_null();
}
}
Arc::new(renamed.finish())
}};
}
if let Some(map) = v.downcast_object_ref::<ValueMap>() {
Ok(rename_rows_by_map!(map))
} else if let Some(map) = v.downcast_object_ref::<MutableMap>() {
Ok(rename_rows_by_map!(map))
} else {
// Try to treat it as a generic iterable
let iter = match v.try_iter() {
Ok(iter) => iter,
Err(_) => {
return Err(Error::new(
ErrorKind::InvalidArgument,
"Table.rename: row_names must be a map or an array",
));
}
};
// Collect the iterator values
let values: Vec<_> = iter.collect();
for i in 0..self.num_rows() {
if let Some(value) = values.get(i) {
if let Some(s) = value.as_str() {
renamed.append_value(s);
} else {
return Err(Error::new(
ErrorKind::InvalidArgument,
format!(
"Table.rename: row_names array must contain only strings, found: {}",View on GitHub (pinned to 0267ce9170)
Solutions
- Pass row_names as a map of old row name to new row name.
- Pass row_names as an array of new row name strings, one per row.
- Omit row_names if you only intend to rename columns.
Example fix
// before
table.rename(None, Some("row0"), false, false)
// after
table.rename(None, Some(vec!["row0"]), false, false) Defensive patterns
Strategy: validation
Validate before calling
fn valid_row_names(v: &Value) -> bool {
v.as_map().is_some()
|| v.as_array().map_or(false, |a| a.iter().all(|x| x.as_str().is_some()))
} Type guard
fn is_row_name_spec(v: &Value) -> bool {
v.as_map().is_some()
|| v.as_array().map_or(false, |a| a.iter().all(|x| x.as_str().is_some()))
} Try / catch
match table.rename(None, row_names, false, false) {
Ok(t) => t,
Err(e) if e.to_string().contains("row_names must be a map or an array") => {
eprintln!("row_names must be a map or array of strings: {e}");
table.rename(None, None, false, false)?
}
Err(e) => return Err(e),
} Prevention
- Always pass a map or a Vec<String> for row_names.
- Don't pass a single row name string; wrap it in a vec.
- Convert dict-based row_names from ported Python agate code to the map form.
When it happens
Trigger: Calling table.rename with row_names set to a scalar, integer, or non-iterable object, e.g. passing a single row name string instead of a list of names.
Common situations: Porting Python agate code that used a dict for row_names; passing a single value when a sequence was expected; config values parsed as the wrong type.
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
- Table.rename: column_names must be a map or an array
- Table.rename: column_names array must contain only strings,
- Table.rename: row_names array must contain only strings, fou
- Table.rename: renamed_columns length ({}) does not match num
- Table.rename: renamed_rows length ({}) does not match number
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/55e277164792c085.
Report an issue: GitHub.