dbt.exceptions.CompilationError: 'list' object has no attribute 'get'
Fixes the CompilationError where Jinja code calls .get on a list, usually because a variable expected to be a dict is actually a list of dicts. Use when the traceback says list object has no attribute get inside a macro or model. Not for Python application code outside dbt templating.
TL;DR
A macro treated a list like a dictionary. Find the variable, check its real shape (often the result of run_query, a var, or modules output is a list of rows), and index or loop it instead of calling .get. Printing the variable with log() during compile shows the true structure fast.
dbt.exceptions.CompilationError: 'list' object has no attribute 'get'Use this when
- dbt compile or run fails with CompilationError list object has no attribute get
- the failing code is a macro iterating config, vars, or a query result
- the error appeared after changing a var from a mapping to a list, or after a package upgrade changed a return type
Not for this skill when
- the object really should be a dict, fix the YAML var definition shape instead of the macro
- the error is dict has no attribute for a different method, inspect that call instead
- you are writing plain Python outside dbt, where this Jinja context does not apply
Steps
Locate the .get call: run dbt compile with --debug, find the macro and line in the traceback, and open that macro. Verify: you know the exact expression calling .get and the variable it is called on.
Add a temporary log call just above it, for example log(varname and varname[0] or var_name, info=true), then compile one model to see whether the value is a list and what its first element looks like. Remove the debug log afterwards. Verify: the logged output shows the real type and shape of the variable.
Fix the access pattern: if it is a list of dicts, loop over items and call .get on each item, or index the intended element first. If it came from run_query, use the table rows or columns API instead of dict access. Verify: the macro accesses elements with the correct type at each step.
Recompile the affected models and run one end to end. Verify: dbt compile and dbt run succeed with no attribute error and the rendered SQL is unchanged apart from the fix.
Variant phrasings
var defined as a list in dbt_project.yml
Vars preserve YAML types. A var written with dash lines is a list even if the macro author expected a mapping; align the macro or the var, and document the shape.
results from a hook
The results object in on-run-end is a list of result objects, not a dict keyed by model. Loop it and filter by node name.
Compatibility: dbt-core 1.x Jinja environment (Jinja2) for macros, models, and hooks; YAML vars keep their YAML types on all adapters.
Why it happens
Jinja in dbt is dynamically typed: nothing stops a macro from calling a dict method on a list until render time. Upstream data shapes (vars, query results, package return values) decide the real type, and when one of them is a list of records rather than a single record, .get fails immediately with this CompilationError.
Edge cases / pitfalls
- An empty list hides the bug until data exists; test the macro with empty and multi-row inputs.
- Chained .get calls fail on the first wrong type, so fixing one call may reveal the next; recompile after each fix.
- Do not convert with a blind dict() call; a list of pairs and a list of dicts need different handling.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstYXRY0q6Eih6QhaHzXwbSA