dbt-labs / dbt-labs/dbt

[v2 Bug] Fusion `dbt retry` does not restore the prior invocation's `--vars`

Open
#15,667 0 comments 0 reactions 1 assignee Claimed by @akbog View on GitHub
area:engine engine:v2 status:triage type:bug
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.