Debugging Data Modeling Errors
This domain (~13% of the exam, roughly 8–10 scored questions on a typical form) tests whether you can look at raw dbt output — an error banner, a stack of Jinja frames, a dbt debug report, or a chunk of logs/dbt.log — and immediately say what stage of the dbt lifecycle failed, why, and which command or config fixes it. Questions are overwhelmingly scenario-based: you are shown an error string and asked for the cause or the next action. The exam rewards precise vocabulary (Parsing Error vs Compilation Error vs Database Error vs Runtime Error), knowledge of where dbt writes artifacts (target/compiled, target/run, logs/dbt.log, run_results.json), and the small set of CLI flags that make debugging faster (dbt compile, dbt debug, dbt parse, --select, --full-refresh, --fail-fast, --debug). Supported version for the exam is dbt 1.11.
Reading dbt compile/run error output: compilation vs database errors
Every dbt invocation moves through fixed stages. The stage at which an error is raised determines the error class, and the error class tells you where to look. Memorize this ordering — it is the single most reusable fact in the domain.
| Stage | What dbt does | Warehouse connection needed? | Typical error class |
|---|---|---|---|
| 1. Flag/config load | Read dbt_project.yml, profiles.yml, CLI flags, env vars | No | Runtime Error (profile/target not found, missing env var) |
| 2. Dependency load | Read package-lock.yml / dbt_packages/ | No | Runtime Error — "dbt found X packages specified… but not installed" → run dbt deps |
| 3. Parse | Read every .sql, .yml, .py, .md; render Jinja to capture ref, source, config; build manifest.json | No | Parsing Error (bad YAML, duplicate resource names, invalid config key) |
| 4. Graph build | Link nodes into the DAG, apply selectors | No | Cycle / dependency errors, invalid selector |
| 5. Compile | Fully render Jinja into executable SQL → target/compiled/ | Yes (introspective macros may query) | Compilation Error |
| 6. Execute | Wrap in materialization DDL → target/run/, send to warehouse | Yes | Database Error |
Where each error class is raised during a dbt invocation
Anatomy of the error banner
Database Error in model dim_customers (models/marts/dim_customers.sql)
001003 (42000): SQL compilation error:
syntax error line 12 at position 4 unexpected 'form'.
compiled Code at target/run/jaffle_shop/models/marts/dim_customers.sql
- Line 1 = error class + resource type + resource name + source file path.
- Middle = the verbatim message. If it carries a vendor error code (Snowflake
001003, BigQuerySyntax error:, PostgresSQLSTATE 42703), it is a Database Error, no matter what the word "compilation" appears inside it. Snowflake calls its own parse failures "SQL compilation error" — that is still a dbt Database Error. This is the exam's favourite distractor. - Last line = pointer to the artifact.
target/run/...for executed nodes (includes thecreate table aswrapper);target/compiled/...fordbt compileand ephemeral/test nodes.
Compilation vs Database at a glance
| Compilation Error | Database Error | |
|---|---|---|
| Raised by | dbt/Jinja, locally | The warehouse, remotely |
| Timing | Before any SQL leaves dbt | After SQL is sent |
| Typical causes | Undefined macro/variable, missing ref target, bad Jinja syntax, disabled model referenced, ambiguous ref | Syntax error, column/relation does not exist, type mismatch, permission denied, divide by zero |
| Artifact to inspect | target/compiled/ may not exist for the node | target/run/<project>/… contains the exact SQL |
| Fix location | .sql Jinja, macros, YAML | SQL logic, upstream data, grants |
Does dbt compile reproduce it? | Yes | No (compile succeeds; it fails only at run) |
Statuses, skips, and exit codes
- A failed model causes all downstream children to be
skipped, not failed. The summary readsDone. PASS=... WARN=... ERROR=... SKIP=... TOTAL=.... - Exit code 0 = success; 1 = handled failure (model error, test failure); 2 = unhandled exception / bad usage.
--fail-fast(-x) aborts the whole run at the first node failure instead of finishing the rest of the DAG.dbt retryre-executes only the nodes that errored or were skipped in the previous invocation, usingtarget/run_results.json. It cannot be used after you change selection logic arbitrarily — it replays the prior run's state.--warn-errorpromotes every warning to an error;--warn-error-optionsscopes that to named warning types.
Common traps
- Treating "SQL compilation error" from Snowflake as a dbt Compilation Error. It is a Database Error.
- Assuming
dbt compilewould have caught a bad column name. It would not — unknown columns are only discovered by the warehouse at run time. - Thinking downstream models "fail" when a parent errors; they are skipped and reported in
SKIP. - Believing a non-zero exit code always means a model broke; a failing test also exits 1.
- Assuming errors abort the run. By default dbt continues building unrelated branches of the DAG unless
--fail-fastis set.
Worked scenario. A run reports ERROR=1 SKIP=7. The error text is Compilation Error in model stg_orders … Model 'model.jaffle.stg_payments' was not found or is disabled. Do you check the warehouse grants, the SQL, or the YAML? The YAML — the message is a Compilation Error naming a missing/disabled node, which means stg_payments is either absent, misspelled in ref, or has enabled: false (often via a +enabled: "{{ target.name == 'prod' }}" config that evaluates false in your target).
Unlock with a paid plan
8 more sections (about 3,851 words) continue below. Every paid plan unlocks all dbt Analytics Engineering Certification study guides, the full question bank and mock exams, from $4.97/month.