{"record":{"id":"3d2087777a88934c","repo":"dbt-labs/dbt-core","slug":"column-name-must-be-a-string","errorCode":null,"errorMessage":"Column 'name' must be a string","messagePattern":"Column 'name' must be a string","errorType":"validation","errorClass":"minijinja::Error (InvalidOperation)","httpStatus":null,"severity":"error","filePath":"crates/dbt-jinja-utils/src/functions/contract_error.rs","lineNumber":160,"sourceCode":"    Ok(Box::leak(Box::new(table)))\n}\n\n/// Helper function to convert Value to Vec<ColumnDefinition>\nfn convert_value_to_column_definitions(value: Value) -> Result<Vec<ColumnDefinition>, Error> {\n    if value.is_undefined() {\n        return Ok(Vec::new());\n    }\n\n    let mut columns = Vec::new();\n\n    match value.try_iter() {\n        Ok(iter) => {\n            for item in iter {\n                let name_value = item.get_attr(\"name\")?;\n                let name = name_value\n                    .as_str()\n                    .ok_or_else(|| {\n                        Error::new(\n                            ErrorKind::InvalidOperation,\n                            \"Column 'name' must be a string\",\n                        )\n                    })?\n                    .to_string();\n\n                let data_type_value = item.get_attr(\"data_type\")?;\n                let data_type = data_type_value\n                    .as_str()\n                    .ok_or_else(|| {\n                        Error::new(\n                            ErrorKind::InvalidOperation,\n                            \"Column 'data_type' must be a string\",\n                        )\n                    })?\n                    .to_string();\n\n                let formatted = item","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-jinja-utils/src/functions/contract_error.rs#L142-L178","documentation":"While converting the model's actual query result columns into contract column definitions (`convert_value_to_column_definitions`, called by `get_contract_mismatches`), each item must expose a `name` attribute that is a string. If `name` is missing or not a string, the library raises this InvalidOperation error because the contract comparison cannot proceed without a usable column name.","triggerScenarios":"`get_contract_mismatches` is called with the model's result columns; an item in the iterated collection either has no `name` attribute or its `name` attribute is a non-string value (e.g. a dict, list, or number) instead of the expected string column name.","commonSituations":"A macro or adapter producing result column objects with malformed/renamed attributes; custom materializations returning rows whose column metadata does not match the expected `name` attribute contract; upstream object shape changes after an upgrade.","solutions":["Ensure the object passed to `get_contract_mismatches` yields items with a string `name` attribute.","Inspect how the columns collection is built (custom materialization/macro) and fix the `name` field.","Verify no macro is overwriting `name` with a non-string value before contract validation.","Upgrade/align adapter versions so column metadata objects match the expected shape."],"exampleFix":"# before (malformed column object)\n{'name': {'first': 'id'}}\n\n# after\n{'name': 'id'}","handlingStrategy":"type-guard","validationCode":"// Validate column objects before calling get_contract_mismatches\ncolumns.iter().all(|c| {\n    c.get_attr(\"name\").ok().and_then(|v| v.as_str().ok()).is_some()\n})","typeGuard":"fn has_string_name(item: &Value) -> bool {\n    item.get_attr(\"name\").ok()\n        .and_then(|v| v.as_str().ok())\n        .is_some()\n}","tryCatchPattern":"match get_contract_mismatches(cols, contract_cols) {\n    Err(e) if e.to_string().contains(\"Column 'name' must be a string\") => {\n        // inspect/normalize the columns collection before retrying\n    }\n    other => other,\n}","preventionTips":["Ensure custom materializations/macros emit column objects with a string `name` attribute.","Type-check result column metadata right after query execution, before contract comparison.","Keep adapter versions aligned so column metadata objects keep the expected shape.","Add a unit test feeding representative column objects into get_contract_mismatches."],"tags":["dbt","jinja","contract","type-mismatch","schema-validation"],"backgroundTag":"type-mismatch","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}