dbt-labs/dbt-core · error

name attribute must be a string

Error message

name attribute must be a string

What it means

Immediately after fetching the column `name` attribute, `reject_partition_field_column` asserts it is a string via `name.as_str().expect("name attribute must be a string")`. This panics when a column's `name` attribute exists but is a non-string Minijinja value (number, mapping, sequence). The comparison against the configured partition field requires a string.

Source

Thrown at crates/dbt-schemas/src/schemas/manifest/bigquery_partition.rs:189

    }

    pub fn reject_partition_field_column(
        &self,
        args: &[MinijinjaValue],
    ) -> Result<MinijinjaValue, MinijinjaError> {
        let mut parser = ArgParser::new(args, None);
        parser.check_num_args(current_function_name!(), 0, 1)?;

        let columns = parser.get::<MinijinjaValue>("columns")?;
        if let Ok(iter) = columns.try_iter() {
            let columns = iter
                .filter(|c| {
                    let name = c
                        .get_attr("name")
                        .expect("column must have a name attribute");
                    !name
                        .as_str()
                        .expect("name attribute must be a string")
                        .eq_ignore_ascii_case(self.field.as_str())
                })
                .collect::<Vec<_>>();
            Ok(MinijinjaValue::from(columns))
        } else {
            Err(MinijinjaError::new(
                MinijinjaErrorKind::InvalidArgument,
                "columns must be a list of Column",
            ))
        }
    }

    /// Return true if the data type should be truncated instead of cast to the data type
    pub fn data_type_should_be_truncated(&self) -> bool {
        !(self.data_type == "int64"
            || (self.data_type == "date"
                && match &self.__inner__ {
                    BigqueryPartitionConfigInner::Time(TimeConfig { granularity, .. }) => {

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Quote numeric or boolean column names in the model/schema YAML (`name: "123"`) so they deserialize as strings
  2. Validate at config-parse time that every column `name` is a string before rendering
  3. In custom adapters/templates, coerce the name with `.to_string()` instead of expecting `as_str()`

Example fix

// before
.as_str().expect("name attribute must be a string")
// after
match name.as_str() {
    Some(s) => !s.eq_ignore_ascii_case(self.field.as_str()),
    None => true,
}
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure every column name deserialized as a string
for col in &model.columns {
    let name = col.get("name").expect("column missing name");
    assert!(name.is_string(), "column name must be a string, got {:?}", name);
}

Type guard

fn column_name_is_string(col: &MinijinjaValue) -> bool {
    col.get_attr("name").map(|n| n.as_str().is_some()).unwrap_or(false)
}

Try / catch

let ok = std::panic::catch_unwind(|| partition_cfg.render(alias));
if ok.is_err() { /* fall back to unfiltered columns */ }

Prevention

When it happens

Trigger: Rendering BigQuery partition SQL where a column entry's `name` resolves to a non-string value — e.g. YAML parsed `name: 2024` or `name: [a, b]` as a number/list, or a custom value object whose `name` attr is not stringifiable.

Common situations: Unquoted numeric column names in schema YAML (e.g. `name: 123`) that YAML deserializes as integers; generated configs injecting non-string names; adapter-specific column objects with structured name fields.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/167fa25c039ea856. Report an issue: GitHub.