Eason09053360 opened a new pull request, #72893:
URL: https://github.com/apache/airflow/pull/72893
`airflow backfill create --dag-id <unknown>` now prints a one-line error and
exits 1 instead of dumping a `DagNotFound` traceback, in both the normal and
`--dry-run` paths.
### Why
Mistyping the Dag id is the most ordinary user error this command can see,
and today it looks like a crash:
$ airflow backfill create --dag-id does_not_exist --from-date 2025-01-01
--to-date 2025-01-02
Traceback (most recent call last):
...
File ".../airflow/models/backfill.py", line 641, in _create_backfill
raise DagNotFound(f"Could not find dag {dag_id}")
airflow.exceptions.DagNotFound: Could not find dag does_not_exist
The model layer raises `DagNotFound` on purpose (it serves both the REST API
and the CLI), and the REST route already maps it to a 404. The CLI handler only
caught `NoBackfillRunsToCreate`, so this exception escaped untranslated. Every
other CLI "Dag does not exist" path (`dags list-jobs`, `dags list-runs`, `dags
state`, ...) already reports it as a plain message on stderr.
The `--dry-run` path had a second wrinkle: `_do_dry_run` is a generator, so
its body (including the Dag lookup that raises) only ran when the result was
iterated, which happened after the `create_session()` block had exited and
outside any `try`.
### What
- Catch `DagNotFound` at the CLI boundary and re-raise it as
`SystemExit(str(e))`, which writes the message to stderr and exits 1, the same
idiom the other CLI "not found" paths use. The exit code is unchanged from the
traceback case, so scripts checking `$?` see no difference.
- In the dry-run branch, consume `_do_dry_run(...)` with `list(...)` inside
the session block and the `try`. Without this the new handler would be
unreachable, because the exception surfaces on iteration, not on the call. As a
side effect the generator now runs while the session it was given is still
open; previously it ran after `session.close()`.
Deliberately out of scope: the sibling validation errors from the same two
model calls (`AlreadyRunningBackfill`, `DagNonPeriodicScheduleException`,
`DagRunTypeNotAllowed`, `InvalidBackfillDateRange`, ...) still surface as
tracebacks. They share the root cause but each needs its own message and test;
this PR only fixes the missing-Dag case. Happy to follow up with the rest if
reviewers prefer one PR.
### How to test
Automated, `airflow-core/tests/unit/cli/commands/test_backfill_command.py`:
- `TestCliBackfill::test_backfill_unknown_dag_shows_friendly_message[False]`
and `[True]` (the `True` case is `--dry-run`). They hit the real database (the
module's `setup_method` empties the `dag` table, so the Dag is guaranteed
missing) and assert `SystemExit` with the Dag id in the message. On `main` both
fail because `DagNotFound` propagates instead.
- `uv run --project airflow-core pytest
airflow-core/tests/unit/cli/commands/test_backfill_command.py -k unknown_dag
-xvs`
- The rest of the file was run as well; the pre-existing `test_backfill*`
cases that mock `_create_backfill` are unaffected (they fail on a non-root host
for an unrelated `triggering_user_name='root'` assumption, and pass in Breeze).
Manual, against a fresh `airflow db migrate` SQLite database (stdout and
stderr captured separately):
- `airflow backfill create --dag-id does_not_exist --from-date 2025-01-01
--to-date 2025-01-02` prints `Could not find dag does_not_exist` on stderr,
nothing on stdout, exit 1 (before: traceback, exit 1).
- Same command with `--dry-run` prints the params block on stdout, then
`Could not find Dag does_not_exist` on stderr, exit 1.
- `--dag-id '[/b]x'` prints `Could not find dag [/b]x` verbatim; square
brackets are not interpreted as rich markup.
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes — Claude Code (Fable 5.1)
Generated-by: Claude Code (Fable 5.1) following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
---
* Read the **[Pull Request
Guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#pull-request-guidelines)**
for more information. Note: commit author/co-author name and email in commits
become permanently public when merged.
* For fundamental code changes, an Airflow Improvement Proposal
([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvement+Proposals))
is needed.
* When adding dependency, check compliance with the [ASF 3rd Party License
Policy](https://www.apache.org/legal/resolved.html#category-x).
* For significant user-facing changes create newsfragment:
`{pr_number}.significant.rst`, in
[airflow-core/newsfragments](https://github.com/apache/airflow/tree/main/airflow-core/newsfragments).
You can add this file in a follow-up commit after the PR is created so you
know the PR number.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]