{"record":{"id":"9d1d17d2b6cc30e8","repo":"dbt-labs/dbt-core","slug":"existing-columns-must-be-iterable-e","errorCode":null,"errorMessage":"existing_columns must be iterable: {e}","messagePattern":"existing_columns must be iterable: (.+?)","errorType":"exception","errorClass":"minijinja::Error::InvalidOperation","httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/adapter/adapter_impl.rs","lineNumber":4652,"sourceCode":"        model_columns: &Value,\n        model_constraints: &Value,\n        contract_enforced: bool,\n        model_name: &str,\n    ) -> Result<Value, minijinja::Error> {\n        use crate::relation::databricks::typed_constraint;\n        use std::collections::{BTreeMap, BTreeSet};\n\n        if self.adapter_type() != Databricks && self.adapter_type() != Spark {\n            return Err(minijinja::Error::new(\n                minijinja::ErrorKind::InvalidOperation,\n                \"parse_columns_and_constraints is only available for Databricks/Spark adapter\",\n            ));\n        }\n\n        let columns: Vec<Column> = existing_columns\n            .try_iter()\n            .map_err(|e| {\n                minijinja::Error::new(\n                    minijinja::ErrorKind::InvalidOperation,\n                    format!(\"existing_columns must be iterable: {e}\"),\n                )\n            })?\n            .map(|v| {\n                v.downcast_object_ref::<Column>().cloned().ok_or_else(|| {\n                    minijinja::Error::new(\n                        minijinja::ErrorKind::InvalidOperation,\n                        \"existing_columns must contain Column objects\",\n                    )\n                })\n            })\n            .collect::<Result<Vec<_>, _>>()?;\n\n        let model_columns_map: BTreeMap<String, DbtColumn> =\n            minijinja_value_to_typed_struct(model_columns.clone()).map_err(|e| {\n                minijinja::Error::new(\n                    minijinja::ErrorKind::SerdeDeserializeError,","sourceCodeStart":4634,"sourceCodeEnd":4670,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/adapter/adapter_impl.rs#L4634-L4670","documentation":"Within parse_columns_and_constraints, the existing_columns argument is iterated via try_iter(); if the Value is not an iterable sequence (e.g. a scalar, dict, or string), the failure is wrapped in an InvalidOperation error stating existing_columns must be iterable. The adapter requires a list-like structure of column objects.","triggerScenarios":"Calling parse_columns_and_constraints with existing_columns as a non-iterable Value: a single object, a dict mapping names to columns, a string, or None.","commonSituations":"Passing a column dict from model.config instead of the relation's column list; forgetting that existing_columns comes from get_columns_in_relation (a sequence); macro refactors that changed the argument shape.","solutions":["Pass the output of get_columns_in_relation(relation) — a sequence of Column objects — as existing_columns.","If you have a dict, convert it to a list of Column objects before calling.","Check the error's inner message for what try_iter rejected and fix the value's type.","Verify macro argument order wasn't swapped between existing_columns and model_columns."],"exampleFix":"// before\ncols = model.columns  # dict, not iterable sequence of Columns\nadapter.parse_columns_and_constraints(cols, model_columns, name)\n\n// after\ncols = adapter.get_columns_in_relation(target_relation)\nadapter.parse_columns_and_constraints(cols, model_columns, name)","handlingStrategy":"validation","validationCode":"def is_iterable_columns(v):\n    try:\n        items = list(v)\n    except TypeError:\n        return False\n    return all(isinstance(i, dict) and 'name' in i for i in items)","typeGuard":"def as_iterable(v):\n    try:\n        return list(v)\n    except TypeError:\n        return None","tryCatchPattern":"try:\n    parsed = adapter.parse_columns_and_constraints(existing, model_columns, name)\nexcept Exception as e:\n    if 'existing_columns must be iterable' in str(e):\n        existing = adapter.get_columns_in_relation(target_relation)\n        parsed = adapter.parse_columns_and_constraints(existing, model_columns, name)\n    else:\n        raise","preventionTips":["Feed existing_columns from get_columns_in_relation, not from config dicts","Verify macro argument order (existing vs model columns)","Add a shape assertion at the top of custom materializations","Don't pass scalars or strings as existing_columns"],"tags":["adapter","databricks","iteration","type-mismatch"],"backgroundTag":"invalid-argument-format","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"}