compilation error" in dbt Jinja: debugging macros
Shows how to debug Jinja compilation errors in dbt macros by reading the compiled SQL and logging render-time values. Use when dbt compile fails on a macro, when rendered SQL looks wrong, or when inheriting mystery macros. Not for runtime warehouse errors, missing models, or syntax tutorials.
TL;DR
Read the compiled SQL first, not the Jinja. dbt renders your macros into plain SQL under target/compiled, and the compilation error almost always becomes obvious once you see the broken output. Add log() calls inside the macro to print values at render time, fix the Jinja, recompile. The loop is fast once you stop guessing at the template.
Compilation Error in macro my_macro (macros/my_macro.sql)
unexpected char '@' at position 42Use this when
- dbt compile or run fails with a Jinja compilation error
- a macro renders SQL that looks wrong but you cannot see why
- you inherited a macro and need to understand what it produces
Not for this skill when
- the SQL compiles but fails at runtime, that is a warehouse error
- the error is "model not found", check ref() spelling instead
- you are writing a macro from scratch and want syntax help, check the Jinja docs
Steps
- Reproduce the failure on one model so the feedback loop stays tight:
dbt compile --select my_modelExpected output: the same compilation error, in seconds. You now have a reproducible case instead of a full-project failure to wade through.
- Find the compiled output dbt managed to render before it died:
find target/compiled -name "*my_model*"Expected output: the rendered SQL file. Read the tail of it, the breakage usually sits right where rendering stopped, which points at the guilty macro call.
- Add log statements inside the macro to see actual values at render time:
-- inside macros/my_macro.sql
{{ log("column list is: " ~ columns | join(", "), info=True) }}Expected output: the logged values print during the next compile. This is printf debugging for Jinja and it works better than staring at the template.
- Check the usual suspects: missing commas in loops and undefined variables:
SELECT
{% for col in columns %}
{{ col }}{{ "," if not loop.last }}
{% endfor %}
FROM {{ ref('stg_orders') }}Expected output: clean comma-separated SQL with no trailing comma. Trailing commas and undefined variables cause the large majority of macro compile errors.
- Recompile until it renders, then run the model to confirm the SQL is not just valid Jinja but valid SQL:
dbt compile --select my_model && dbt run --select my_modelExpected output: compilation succeeds and the model builds. Remove or quiet the log statements before committing so the next person's logs stay clean.
Variant phrasings
dbt macro unexpected character error
The Jinja parser hit something it cannot tokenize. Step 2 shows where rendering stopped, which is usually one line above the real problem.
dbt undefined variable in macro
A var() or macro argument that was never passed. The log trick from step 3 prints what the macro actually received, which settles it fast.
how to debug dbt jinja whitespace
Whitespace control with dash markers changes the rendered SQL invisibly. Compare the compiled output with and without the dashes to see the difference.
Why it happens
Jinja renders templates to text before the database ever sees SQL, so a compilation error means the template itself is broken, not the query logic. The error message points at a template position, but templates compose macros inside macros, so the real fault is often two includes up from where it surfaces. Rendered output plus logging collapses that indirection into something readable.
Edge cases
- Macro dispatch across packages can resolve to a different macro than the one you are reading. Check the dispatch config when the code looks right.
- Whitespace-only changes can break SQL that depends on newlines. Render and diff instead of eyeballing.
- log() with info=True prints to stdout, without it the message hides in the debug logs where you will never see it.
- Compilation errors in tests surface with the test name, not the macro name. Trace through the test's ref chain to find the macro.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_ShtUzrHgss6kK-XI2dfwyA
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.