dagster-dbt: Surface dbt CLI failures during selection (prevents StopIteration in multiprocess) Fixes #33380#33478
Conversation
…agster-io#33380) - Fix _select_unique_ids_from_cli swallowing dbt CLI failures which caused StopIteration / RuntimeError in multiprocess_executor - Raise underlying invocation.get_error() when available - Add fallback RuntimeError when CLI fails without error - Add comprehensive tests for: - successful parsing - empty/partial events - failure with explicit error - failure without error Fixes dagster-io#33380
Greptile SummaryThis PR fixes a bug in Confidence Score: 5/5Safe to merge — the fix correctly surfaces previously-swallowed dbt CLI errors with no behavioral regressions on the success path. The change is minimal and targeted. The _error_messages instance field is populated during the first _stream_stdout() call and persists when is_successful() calls _stream_stdout() again on a closed pipe, so failure detection remains correct. The raise err or RuntimeError(...) idiom is valid Python. Tests cover all four relevant cases: success, empty/malformed events, failure with explicit error, and failure without error. No P0/P1 findings. No files require special attention.
|
| Filename | Overview |
|---|---|
| python_modules/libraries/dagster-dbt/dagster_dbt/utils.py | Adds is_successful() check after consuming _stream_stdout() to surface dbt CLI failures instead of silently returning an incomplete unique_id set |
| python_modules/libraries/dagster-dbt/dagster_dbt_tests/core/test_utils.py | New test file with 5 unit tests covering success, empty/malformed events, failure with error, failure without error, and partial stdout failure scenarios |
Sequence Diagram
sequenceDiagram
participant S as select_unique_ids
participant CLI as _select_unique_ids_from_cli
participant INV as DbtCliInvocation
participant PROC as dbt Process
S->>CLI: call (dbt Fusion path)
CLI->>INV: DbtCliResource(...).cli(cmd)
INV->>PROC: spawn process
CLI->>INV: _stream_stdout()
INV->>PROC: read stdout (generator)
PROC-->>INV: raw events; _error_messages populated
Note over INV: stdout pipe closed after generator exhausted
CLI->>INV: is_successful()
INV->>INV: _stream_stdout() → empty (stdout closed)
INV->>PROC: process.wait() → exit code
INV-->>CLI: True / False
alt is_successful() == False
CLI->>INV: get_error()
INV-->>CLI: Exception or None
CLI->>S: raise err or fallback RuntimeError
else is_successful() == True
CLI->>S: return unique_ids - {None}
end
Reviews (2): Last reviewed commit: "test(dagster-dbt): cover partial stdout ..." | Re-trigger Greptile
|
Hi @OwenKephart — this PR has been open since Feb 22 and the linked bug (#33380) is still open. It's a small fix to dagster-dbt that surfaces dbt CLI failures during _select_unique_ids_from_cli instead of silently swallowing them, preventing misleading StopIteration errors during multiprocess execution. Automated review gave it a 5/5. Would appreciate a look when you get a chance! |
cmpadden
left a comment
There was a problem hiding this comment.
The main change in python_modules/libraries/dagster-dbt/dagster_dbt/utils.py looks correct to me. Checking invocation.is_successful() after consuming _stream_stdout() addresses the actual bug and should surface the underlying dbt CLI failure instead of letting it turn into a downstream StopIteration/RuntimeError.
One small thing I’d ask about is the unrelated change in python_modules/libraries/dagster-dbt/dagster_dbt/asset_utils.py. I don’t think it introduces a regression, since the old code already failed on empty metadata_by_key, but the new error message is a bit misleading for valid @dbt_assets defs whose selection yields no asset specs, for example test-only selections. It may be worth either:
- tightening the message to mention that the selection may have matched only non-asset dbt nodes, or
- splitting that change into a separate PR since it’s not directly part of the CLI failure fix.
The tests in python_modules/libraries/dagster-dbt/dagster_dbt_tests/core/test_utils.py look adequate for the bug being fixed. I don’t see a blocker here.
The defensive guard added to `get_manifest_and_translator_from_dbt_assets` was not part of the CLI failure fix and had a misleading error message. The root cause fix in utils.py makes the downstream guard unnecessary. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for the review @cmpadden! You're right — the asset_utils.py change was addressing the I've removed the asset_utils.py change — the PR now only contains the utils.py fix and the |
|
Thanks for the fix here. The production change in
Recommended change: update the tests to patch |
cmpadden
left a comment
There was a problem hiding this comment.
See comment. Thank you.
|
Updated the tests to patch |
Fixes #33380
Summary
Fixes an issue where dbt CLI failures during
_select_unique_ids_from_cliwere silently swallowed, leading to empty metadata and downstreamStopIteration/RuntimeErrorduring multiprocess execution.Root cause
When
DbtCliInvocationfailed (non-zero exit), the code continued processing_stream_stdout()without checkingis_successful(). This produced incomplete/emptyunique_idsets, causing failures later in repository reconstruction undermultiprocess_executor.Fix
_stream_stdout(), explicitly checkinvocation.is_successful()invocation.get_error()when availableRuntimeError("dbt invocation failed but no error was captured")Tests
Added comprehensive unit tests covering:
Impact
StopIteration/ generator errorsdagster devwithmultiprocess_executor