[v2 Bug] Fusion `dbt retry` does not restore the prior invocation's `--vars`
- Dominant language
- Rust
- Stars
- 13.8k
- Forks
- 2.6k
- Avg merge
- 21h 31m
- Merged PRs (30d)
- 56
Description
### Is this a new bug in dbt v2.x compared to the latest version of dbt 1.x?
- [x] I believe this is a new bug in dbt v2.x
- [x] I have searched the existing issues and could not find a duplicate
### Current Behavior
`dbt retry` does not restore the `--vars` passed to the command it is retrying. On Fusion, `run_results.json`'s `args` block persists only a minimal set of flags —
```
command full_refresh static_analysis which
```
— with **no `vars` key** (and no `select`/`exclude`). `dbt retry` reconstructs the prior command from that block, so every model/test/hook re-rendered by the retry sees `var()` fall back to its default, not the value supplied to the original invocation. dbt-core, by contrast, serializes the full args dict (including `vars`) into `run_results.json` and reconstructs the vars on retry.
This is silent: there is no warning that the retried command is running with a different variable context than the command it claims to be retrying.
### Expected Behavior
`dbt retry` re-executes the failed/skipped nodes with the **same** variable context as the invocation it is retrying — i.e. the prior command's `--vars` are restored automatically (matching dbt-core behavior). Retry is documented as "re-run the last command"; a var-dependent node must resolve identically on retry.
### Steps To Reproduce
Deterministic. Any adapter (BigQuery shown; the var substitution is adapter-independent).
1. Add a model whose compiled SQL embeds a var, and which fails deterministically so retry has something to re-run. Embedding the var in a deliberately non-existent relation name makes the applied value visible in the error message:
```sql
-- models/zz_retry_probe.sql
{{ config(materialized='table', static_analysis='off') }}
select 1 as id, '{{ var("probe_val", "DEFAULT_NO_VARS") }}' as probe_marker
from `my-project.my_dataset.zz_nonexistent_{{ var("probe_val", "DEFAULT_NO_VARS") }}`
```
2. Build it with an explicit var:
```
dbt build --select zz_retry_probe --vars '{"probe_val": "INJECTED_FROM_BUILD"}'
```
→ fails with `Not found: Table ...zz_nonexistent_INJECTED_FROM_BUILD` (var applied ✅).
3. Retry, exactly as documented (no need to re-supply anything):
```
dbt retry
```
→ **fails with `...zz_nonexistent_DEFAULT_NO_VARS`** — the var was dropped, `var()` fell back to its default.
4. (Control — confirms the fix path.) Re-passing `--vars` on the retry works:
```
dbt retry --vars '{"probe_val": "RETRY_EXPLICIT_VARS"}'
```
→ fails with `...zz_nonexistent_RETRY_EXPLICIT_VARS`.
Inspecting `target/run_results.json` after step 2 shows the `args` block contains no `vars` key at all (`jq '.args | keys' target/run_results.json`).
### Relevant log output
```shell
# Step 2 — dbt build --vars '{"probe_val": "INJECTED_FROM_BUILD"}'
[error] [DbDriverFailed (dbt1308)]: ... Error 404: Not found: Table
my-project:my_dataset.zz_nonexistent_INJECTED_FROM_BUILD ...
# Step 3 — dbt retry (no vars re-passed)
[error] [DbDriverFailed (dbt1308)]: ... Error 404: Not found: Table
my-project:my_dataset.zz_nonexistent_DEFAULT_NO_VARS ...
# run_results.json from step 2
$ jq -c '.args | keys' target/run_results.json
["command","full_refresh","static_analysis","which"]
```
### Environment
```markdown
- OS: Ubuntu 24.04 / Linux (also reproduces on GitHub Actions `ubuntu-latest`)
- CPU: x86_64
- dbt distribution and version: dbt-fusion 2.0.0-preview.202 (also observed on 2.0.0-preview.199 in CI)
```
### Which database adapter are you using?
bigquery
### Is this a discrepancy vs. dbt 1.x?
- [x] Yes — this works in dbt 1.x but not in dbt v2.x
### Additional Context
Real-world impact that surfaced this: our Slim-CI job runs `dbt build --select state:modified+ --defer … --vars '{"disable_dbt_artifacts_autoupload": true, "disable_run_results": true, "disable_dbt_invocation_autoupload": true}'`.
Those vars gate the Elementary observability package's `on-run-end` upload hooks. When a (separate, known) fresh-dataset relation-cache 404 trips an in-job `dbt retry`, the retry drops the vars → the `disable_*` flags revert to `false` → Elementary's `on-run-end` hooks (`upload_dbt_artifacts` / `upload_run_results` / `upload_dbt_invocation`) fire during the retry and write to a `_elementary` dataset that the CI pipeline never provisions, producing a `Dataset …_elementary not found` cascade. `on-run-end` hooks run at the end of *any* node-executing invocation, retry included, so any project that toggles hook/materialization behavior via `--vars` is exposed — the failure is not specific to Elementary.
The general risk is broader than a spurious CI failure: a var that changes *model logic* (e.g. an incremental cutoff date, a feature flag, an environment switch) will silently materialize different data on retry than on the original run.
Contributor guide
Assessment
This issue has not been assessed yet.