dbt-labs/dbt-core · error
Table.rename: column_names array must contain only strings,
Error message
Table.rename: column_names array must contain only strings, found: {} What it means
When column_names is given as an array to Table.rename, every element must be a string (the new column name). The library found a non-string element while assigning new names positionally and includes the offending value in the message.
Source
Thrown at crates/dbt-agate/src/table.rs:693
// 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: column_names must be a map or an array",
));
}
};
let mut renamed = old;
for (i, value) in iter.enumerate() {
if i >= renamed.len() {
break;
}
if let Some(s) = value.as_str() {
renamed[i] = s.to_string();
} else {
return Err(Error::new(
ErrorKind::InvalidArgument,
format!(
"Table.rename: column_names array must contain only strings, found: {}",
value
),
));
}
}
Ok(renamed)
}
})
.transpose()?;
// Renaming of rows
let old_row_name = |i| -> Option<&str> {
self.repr.row_names.as_ref().and_then(|names| {
if names.as_ref().is_valid(i) {
Some(names.value(i))View on GitHub (pinned to 0267ce9170)
Solutions
- Ensure every element of the column_names array is a string before calling rename.
- Convert numeric or other elements with a string conversion step, e.g. value.to_string().
- Use the map form {"old": "new"} instead if you want selective renaming.
Example fix
// before rename(Some(vec!["a", 2]), None, false, false) // after rename(Some(vec!["a", "b"]), None, false, false)
Defensive patterns
Strategy: type-guard
Validate before calling
let all_strings = column_names.iter().all(|v| v.as_str().is_some());
if !all_strings { panic!("column_names must contain only strings"); } Type guard
fn all_strings(v: &[Value]) -> bool {
v.iter().all(|x| x.as_str().is_some())
} Try / catch
match result {
Err(e) if e.to_string().contains("array must contain only strings") => {
let coerced: Vec<String> = raw_names.iter().map(|v| v.to_string()).collect();
table.rename(Some(coerced), None, false, false)?
}
other => other?,
} Prevention
- Stringify all elements before building the names array.
- Avoid mixing typed values and strings in name lists.
- Add a unit test asserting every element is a string.
When it happens
Trigger: Calling table.rename with an array column_names containing numbers, nulls, booleans, or nested values, e.g. ["a", 2, null].
Common situations: Programmatically building the name list from mixed sources (parsed CSV headers mixed with placeholders); JSON config where names were numbers; forgetting to stringify values read from a config file.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Table.rename: row_names array must contain only strings, fou
- Table.rename: column_names must be a map or an array
- Table.rename: row_names must be a map or an array
- 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/e2601aafa6a4e6a4.
Report an issue: GitHub.