Troubleshooting and optimizing dbt pipelines: sample questions

3 free practice questions on troubleshooting and optimizing dbt pipelines, one of the seven topics in the official v1.11 outline for the dbt Analytics Engineering Certification Exam — an estimated 6% of the exam, or about 4 of its 65 questions. Answers, reasoning and documentation links are all on this page.

Last updated . We revise these pages whenever dbt Labs revises the exam.

SHARE OF THE EXAM~6%our estimate
QUESTIONS HERE31 with runnable SQL
FORMATS SHOWN2of 6 on the exam

What this topic covers

A small topic with two subtopics: managing failure points in the DAG, and using dbt clone.

SUBTOPICS, FROM THE OFFICIAL OUTLINE · 2

  1. 01Troubleshooting and managing failure points in the DAG
  2. 02Using dbt clone

Where the marks go

Two ideas carry it. First, an errored node is a node-level failure, not a run-level abort — dbt continues through the rest of the DAG and marks only that node's dependents as skipped, unless you pass --fail-fast. The discrete-option question below tests the consequences one statement at a time.

Second, dbt clone does not rebuild anything. It points at the relations recorded in the state manifest you hand it, which means a QA schema stood up by cloning holds production's data as of production's last run — not as of now, however many rows have landed since.

3 sample questions, with answers

Nothing is hidden. Each question shows the correct answer, why it is right, why every other option is wrong, and the documentation page that settles it. Where the answer is a claim about SQL behaviour, there is a query you can run in the browser against a small sample schema.

Q1Multiple choiceMedium

A nightly dbt build --no-fail-fast finishes with this summary line. The two WARN results are generic tests configured with severity: warn. Which statement regarding this run is true?

Finished running 38 models, 2 snapshots, 10 tests in 0 hours 6 minutes and 12.44 seconds (372.44s).
Completed with 1 error and 2 warnings:
Done. PASS=41 WARN=2 ERROR=1 SKIP=6 TOTAL=50
  • The 6 SKIP nodes are every node that had not started when the error occurred.
  • The 6 SKIP nodes are all downstream of the node counted in ERROR.CORRECT
  • The 2 WARN results are tests that returned failing rows at default severity.
  • The 2 WARN results each skipped the models downstream of them.

WHY

The summary line buckets every selected node exactly once, and the four counts sum to TOTAL (41+2+1+6=50). SKIP counts nodes dbt never executed because something they depend on did not succeed — the build docs state that a failure blocks downstream resources and causes them to 'skip entirely' (e.g. if model_b depends on model_a and a unique test on model_a fails, model_b will SKIP). Here only one node is counted in ERROR, and the two WARN results come from tests set to severity: warn, which the same page says is how you stop a test from causing skipping. Fail-fast is explicitly off — --no-fail-fast sets the flag to false at the CLI, which takes precedence over any environment variable or dbt_project.yml setting — so nodes were only skipped for dependency reasons, not because dbt stopped early. So the only blocking failure in the run is the ERROR node, and all 6 skipped nodes are its descendants (directly, or through another skipped node). That is what a non-zero SKIP buys you when triaging: it is a count of unrun work traceable to an upstream failure, not of work that ran badly.

WHY THE OTHERS ARE WRONG

The 6 SKIP nodes are every node that had not started when the error occurred.
That describes fail-fast behavior, which this invocation explicitly disables: --no-fail-fast sets the fail_fast flag to false at the CLI, and CLI options take the highest precedence over environment variables and dbt_project.yml. With fail-fast off, dbt keeps executing nodes that do not depend on the failed one, so SKIP=6 is the count of that node's descendants, not the count of everything left in the run.
The 2 WARN results are tests that returned failing rows at default severity.
Default severity is error, not warn: a test that returns failing rows at default severity is a failure and lands in the ERROR bucket. A result only lands in WARN when severity is warn, or when the failure count clears warn_if but stays under error_if.
The 2 WARN results each skipped the models downstream of them.
Warn-severity tests are exactly the case the build page says does not cause skipping — its advice for 'don't want a test to cause skipping?' is to adjust severity or thresholds to warn instead of error. The two WARN results therefore did not themselves block anything downstream. Whether a given model below them ran still depends on its other ancestors: one that also depends on the ERROR node is among the 6 SKIPs.
Q2Multiple choiceMediumRunnable proof

Your project runs on Snowflake. In production, fct_orders is materialized as a table and stg_orders as a view. Neither relation exists yet in your dev schema. From your dev target you run dbt clone --state prod-artifacts --select stg_orders fct_orders. Which statement regarding the relations created in dev is true?

  • fct_orders is a zero-copy clone; stg_orders is skipped as a non-cloneable node.
  • fct_orders is a zero-copy clone; stg_orders is a view pointing at the production relation.CORRECT
  • fct_orders is a zero-copy clone; stg_orders is rebuilt by executing its model SQL.
  • Both relations are created as views pointing at the production relations.
  • Both relations are created as zero-copy clones of the production relations.

WHY

The clone docs state the rule as a two-part conditional, applied per node: 'If your data platform supports zero-copy cloning of tables (Snowflake, Databricks, or BigQuery), and this model exists as a table in the source environment, dbt will create it in your target environment as a clone. Otherwise, dbt will create a simple pointer view (select * from the source object).' Snowflake satisfies the platform half for both nodes. fct_orders also exists as a table in production, so it meets both conditions and is created in dev as a clone. stg_orders fails the second half — it is a view in production, not a table — so it lands in the documented 'otherwise' branch: a pointer view over the production relation. Because neither relation already exists in dev, the other documented default — 'dbt clone will not recreate pre-existing relations in the current target' — does not intervene, and both relations are created. One clone command can therefore leave two different object types in the same dev schema.

WHY THE OTHERS ARE WRONG

fct_orders is a zero-copy clone; stg_orders is skipped as a non-cloneable node.
dbt does not skip nodes that cannot be zero-copy cloned. The clone materialization has a documented fallback — a view referencing the source relation — so stg_orders is still created in the dev schema.
fct_orders is a zero-copy clone; stg_orders is rebuilt by executing its model SQL.
The documented fallback is not a rebuild: dbt creates 'a simple pointer view (select * from the source object)'. The view's definition selects from the existing production relation — it is not the model's own SQL being executed against dev, which is what dbt run would do.
Both relations are created as views pointing at the production relations.
The view fallback applies only to nodes that fail the table-and-platform test. fct_orders is a table on a platform that supports zero-copy cloning, so it is cloned rather than pointed at.
Both relations are created as zero-copy clones of the production relations.
Platform support alone is not sufficient. Snowflake can zero-copy clone tables, but stg_orders is a view in the source environment, so the second condition fails and dbt creates a pointer view instead.
Q3Discrete option (DOMC)Medium

In a nightly dbt build that succeeded on previous nights, stg_orders errors and fct_orders, a table model that refs it, is marked SKIP. You will be shown statements about fct_orders and how that run ends, one at a time. For each statement, answer YES if it is true, NO if it is false.

In the exam these appear one at a time and you answer YES or NO to each, without seeing the rest. All of them, with their answers, are below.

  • No SQL for fct_orders runs, so its table still holds the data from the previous buildYES
  • dbt retry re-runs stg_orders and, if it now succeeds, builds fct_orders without rerunning the models that already succeededYES
  • dbt creates fct_orders as an empty table so that downstream refs still resolveNO
  • The invocation exits with code 0, since a skip is not an errorNO
  • The non-zero exit code comes from the error on stg_orders, not from the skipYES

WHY

SKIP means the node never executed. dbt blocks a failed node's dependents from running and they 'skip entirely' — no CREATE, no INSERT, no query of any kind is sent for fct_orders, so the table the previous nights' successful builds left in the warehouse is still sitting there untouched, now silently one night staler than the schedule promises (a). That skip state is written to target/run_results.json, which is exactly what dbt retry reads: 'Retry re-executes the last invocation from the point of failure', referencing run_results.json to determine where to start — the failed stg_orders and the nodes that skipped behind it — rather than rerunning the models that already succeeded. The condition in the statement matters: 'Executing retry without correcting the previous failures yields idempotent results', so if stg_orders errors again, fct_orders skips again; only when the retried stg_orders succeeds does fct_orders build (b). On exit codes, dbt returns 1 when the invocation completes with at least one handled error — the docs describe that case as the run completing while 'some models may have been skipped'. The skip is a downstream consequence of the handled error on stg_orders, which is what drives the non-zero code (e).

WHY THE OTHERS ARE WRONG

dbt creates fct_orders as an empty table so that downstream refs still resolve
dbt does not stand in an empty placeholder for a skipped node. The node is blocked from running at all, so nothing is created or replaced — an empty table would be worse than a skip, because downstream models would build cleanly on zero rows and publish an empty mart instead of failing loudly.
The invocation exits with code 0, since a skip is not an error
A zero exit code always implies success. This run had a handled error (stg_orders), so dbt exits 1; skips are reported alongside that error, not as a clean outcome.

Know whether troubleshooting and optimizing dbt pipelines is actually costing you marks.

The free readiness check is weighted like the real exam across all seven topics, so it tells you where you stand on this topic relative to the rest — which is the only version of that question worth answering before you book.

Take the free readiness check20 questions · ~15 minutes · no card

The other six topics

Keep reading

SOURCES

Every source above was read in full and last checked on .