dbt — Troubleshooting
"Compilation Error: Circular dependency detected"
This means two or more models reference each other, directly or through a chain, in a way that has no valid execution order — Model A's ref() depends on Model B, which somewhere in its own logic depends back on Model A. dbt cannot resolve this into a valid DAG and fails at compile time rather than at runtime, which is actually the better failure mode (caught before wasting warehouse compute). The fix requires restructuring the actual logic — usually extracting the genuinely shared logic both models need into a separate upstream model that both A and B can depend on independently, rather than having them depend on each other; dbt ls --select +model_name+ shows a model's full upstream and downstream dependency chain and is the fastest way to actually trace where the cycle originates rather than guessing.
An incremental model has silently accumulated duplicate rows
If an incremental model's row count is growing faster than expected relative to actual new data, the near-certain cause is a missing or incorrect unique_key config (covered on the Intermediate tab) — without it, dbt's incremental logic simply appends every "new" row matching the incremental filter, including rows that are actually updates to existing records rather than genuinely new ones, producing duplicates rather than merges. Confirm unique_key is set and actually matches a column (or column combination) that's genuinely unique per logical record — a unique_key set to a non-unique column produces the exact same silent duplication problem, just for a different underlying reason. Once duplicates already exist in a production table, a dbt run --full-refresh for that specific model rebuilds it from scratch with the corrected config, clearing the accumulated duplicates — but this can be expensive for a large table, which is exactly why catching an incorrect unique_key at model-review time, before it ships, matters more than fixing it after the fact.
A model that worked yesterday now fails to compile after a schema change
If a model suddenly can't find a column it references, and nothing in the model's own SQL changed, the upstream source schema itself likely changed — a column was renamed, dropped, or a source table's structure otherwise shifted upstream of dbt's control. dbt source freshness and reviewing the actual current source schema (not just trusting a source's declared schema.yml, which can drift out of sync with reality if not actively maintained) is the fastest way to confirm this as the cause. This is the direct, practical argument for the staging-layer convention from the Fundamentals tab — a schema change ideally only requires fixing the one staging model that directly wraps that source, not every downstream mart that transitively depends on it, precisely because everything downstream goes through ref() to the staging model rather than referencing the raw source directly.
`dbt test` fails in CI but the model appears correct when checked manually
A test failing in CI but not reproducing on manual inspection often comes down to a timing/data-freshness mismatch — CI ran against data that was in a genuinely different (often mid-load, partially-updated) state than what's visible during a later manual check, particularly for a source table that's actively being written to during the CI run's execution window. Confirming the exact data state at the time of the CI failure (checking the test query's actual result set at that point, not re-running it later against now-different data) is necessary before concluding the test itself is flawed — a test correctly catching genuine transient bad data during a specific load window is a different, real finding from a poorly-written test producing false positives, and conflating the two leads to either ignoring a real intermittent data quality issue or unnecessarily weakening a genuinely correct test.
`dbt run` is taking dramatically longer than it used to, with no obvious project change
The most common real cause is data volume growth outpacing the current materialization strategy — a model materialized as table (full rebuild every run) that was fine at a smaller data volume becomes a real bottleneck once the underlying source table has grown substantially, and the fix is switching that specific model to incremental materialization (covered on the Intermediate/Advanced tabs) rather than assuming something about the SQL itself regressed. Checking dbt run timing per-model (dbt's own run output reports per-model execution time) reveals which specific model is actually the slow one, rather than treating "the whole run is slower" as one undifferentiated problem — very often it's one or two specific large models responsible for the majority of the increase, not a uniform slowdown across the whole project.

