Runtime Error in model: 'dict' object has no attribute 'database' in ref()
Fixes the Runtime Error where ref returns something unexpected and code reads .database on a dict, inside a model or macro. Use when the traceback says dict object has no attribute database in ref. Not for missing refs, which fail with a different compilation message.
TL;DR
Code called ref and then treated the result as a relation object, but in the context where it ran, ref returned a dict (the node representation) or the code shadowed ref. Use the right API for the context: in model SQL, ref gives a relation you can select from; in Python-ish contexts and hooks you get node dicts. Split the logic so each context uses its own shape.
Runtime Error in model: 'dict' object has no attribute 'database' in ref()Use this when
- dbt run fails with Runtime Error in model dict object has no attribute database in ref()
- a macro or hook reads ref(...).database or .schema directly
- the same code works in a model but fails in a hook, or the reverse
Not for this skill when
- the ref target does not exist, dbt reports that as a compilation dependency error instead
- you only need the relation name as text, use the string form of ref in SQL rather than attribute access
- the error is on a source call, sources return relations with the same context rules; check which call is really failing
Steps
Find the attribute access: grep the project for .database and .schema usages near ref or source calls, and note whether each site is model SQL, a macro called at compile time, or an on-run hook. Verify: each attribute access is classified by the context it runs in.
For compile-time macros, obtain relation metadata through the adapter instead: use adapter.getrelation with database, schema, and identifier parts taken from the node dict keys, or read graph nodes via the graph object where dict access is correct. Verify: compile-time code reads dict keys for node data and uses getrelation for warehouse metadata.
For model SQL, keep it simple: select from the ref directly and avoid attribute access entirely unless you use the documented relation attributes available in that context. Verify: model SQL compiles to the fully qualified relation name.
Compile and run one model per fixed context, including a run that triggers the hook if a hook was changed. Verify: dbt compile and the full run succeed with correct relation names in the compiled SQL.
Variant phrasings
broke after moving code from a model into a macro
Moving code changes its execution context and the type ref returns. Moving logic is the trigger; audit every ref and source call in the moved block.
execute flag changes behavior
At parse time many objects are placeholders. Guard metadata lookups with if execute so parse-only commands do not hit the dict path.
Compatibility: dbt-core 1.x Jinja contexts for models, macros, and hooks; adapter.get_relation available on all adapters. Node dict keys include database, schema, and alias fields.
Why it happens
ref is context dependent. In rendered model SQL it produces a relation object, while in graph and hook contexts the underlying node is a manifest dict. Code written against one shape and executed in the other asks a dict for object attributes, and Jinja raises this Runtime Error at render or run time.
Edge cases / pitfalls
- String interpolation of a dict prints the whole dict into SQL; always check compiled output after touching this code.
- The graph object structure shifts slightly between dbt versions; pin attribute reads to documented keys.
- Do not monkey-patch by defining your own ref; fix the call sites.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_W8lnzAGnVxP2XYuxsvbbSg