dbt-labs/dbt-core · error
time_partitioning_field must be a string
Error message
time_partitioning_field must be a string
What it means
`PartitionConfig::render` panics when time-ingestion partitioning is active and `time_partitioning_field()` returns a value that is not a string (`expect("time_partitioning_field must be a string")`). The rendered column expression (`alias.field`) requires the time-partitioning field to be a plain string; anything else is treated as a corrupted partition config.
Source
Thrown at crates/dbt-schemas/src/schemas/manifest/bigquery_partition.rs:240
Self::PARTITION_TIME
};
Ok(MinijinjaValue::from(field))
}
/// Return the insertable time partitioning field name based on the data type.
/// Practically, only _PARTITIONTIME works so far.
pub fn insertable_time_partitioning_field(&self) -> Result<MinijinjaValue, MinijinjaError> {
Ok(MinijinjaValue::from(Self::PARTITION_TIME))
}
/// Render the partition expression
pub fn render(&self, alias: Option<String>) -> Result<MinijinjaValue, MinijinjaError> {
let column = if !self.time_ingestion_partitioning() {
self.field.to_owned()
} else {
self.time_partitioning_field()?
.as_str()
.expect("time_partitioning_field must be a string")
.to_owned()
};
let column = if let Some(alias) = &alias {
format!("{alias}.{column}")
} else {
column
};
let result = if self.data_type_should_be_truncated() {
format!(
"{}_trunc({}, {})",
self.data_type,
column,
self.granularity()?
)
} else {
columnView on GitHub (pinned to 0267ce9170)
Solutions
- Set `time_ingestion_partitioning` (or `time_partitioning_field`) in the model config as a plain quoted string column name
- Validate the partition config shape before rendering (field must be a string when time-ingestion partitioning is enabled)
- If you construct `PartitionConfig` programmatically, coerce the field with `.to_string()` before calling `render`
Example fix
// before
self.time_partitioning_field()?.as_str().expect("time_partitioning_field must be a string").to_owned()
// after
match self.time_partitioning_field()?.as_str() {
Some(s) => s.to_owned(),
None => return Err(MinijinjaError::new(...)),
} Defensive patterns
Strategy: validation
Validate before calling
// before rendering
if cfg.time_ingestion_partitioning() {
let f = cfg.time_partitioning_field().ok_or("missing field")?;
if f.as_str().is_none() {
return Err("time_partitioning_field must be a string".into());
}
} Type guard
fn has_string_time_field(cfg: &PartitionConfig) -> bool {
!cfg.time_ingestion_partitioning()
|| cfg.time_partitioning_field().and_then(|v| v.as_str()).is_some()
} Try / catch
match std::panic::catch_unwind(|| cfg.render(Some(alias))) {
Ok(v) => v,
Err(_) => MinijinjaValue::from(""), // or propagate a proper error
} Prevention
- Configure time_ingestion_partitioning with a plain quoted column-name string
- Validate partition config shape in a pre-render config pass
- When building PartitionConfig programmatically, store the field via to_string()
When it happens
Trigger: Calling `render`/`render_`/`render_wrapped` on a `PartitionConfig` where `time_ingestion_partitioning()` is true but `time_partitioning_field` yields a non-string Minijinja value — e.g. `time_ingestion_partitioning` config set with a structured/None field value instead of a column name string.
Common situations: Model config like `time_ingestion_partitioning:` with a misconfigured or empty field; configs produced by another tool or older dbt version storing the field as a non-string; YAML that deserialized the field as a number or mapping.
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
- when data_type is date, inner must be a TimeConfig
- adapter.parse_partition_by failed on {raw_partition_by:?}: {
- column must have a name attribute
- unknown table type: {type_string}
- Expect a BigqueryPartitionConfigStruct
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/8e1848350c0e0c7d.
Report an issue: GitHub.