You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@airflow.apache.org by Eason陳永承 <ea...@gmail.com> on 2026/08/28 04:38:52 UTC
[DISCUSS] Aligning "not found" behaviour in the airflow CLI
Hi all,
While fixing `airflow config get-value` (PR #72145
<https://github.com/apache/airflow/pull/72145#issuecomment-5438953827>) I
was asked to check
the wider picture before changing something that is part of the Public
Interface. Here is what I found.
## The observation
For commands that take an identifier, look one thing up and print it to
stdout -- the ones people wrap in `v=$(airflow ...)` -- "target does not
exist" is handled inconsistently. Measured on main, in Breeze, against a
migrated metadata DB:
command (target missing) exit stdout stderr
------------------------------- ---- --------- -------------------
variables get 1 (empty) clean message
pools get 1 (empty) clean message
connections get 1 (empty) clean message
providers get 1 (empty) clean message
dags details 1 (empty) clean message
assets details 1 (empty) clean message
dags state (dag missing) 1 (empty) clean message
tasks states-for-dag-run 1 (empty) 1126-byte traceback
dags state (dag ok, run gone) 0 "None" (empty)
config get-value 0 (nothing) (nothing)
Two things stand out:
1. `config get-value` exits 0 and prints nothing at all, so a caller
cannot tell a missing option from an option set to the empty string.
It also let the config parser's "not found" warning reach *stdout*,
corrupting the one stream the command exists to produce.
2. `airflow dags state <dag> <bad-run-id>` prints the literal string
"None" and exits 0. git log suggests this was never a decision:
#21793 (2022) added a SystemExit for the missing-DAG case in the same
function but left this branch alone, and #46407 (2025) mechanically
preserved it while refactoring for null logical dates. It looks like
the accidental output of str(None).
## The convention already exists
- The Stable REST API returns 404 "Option [section/option] not found."
for the config case.
- `airflowctl config get` is generated over that API, so it already
surfaces the error.
- 8 of the 10 cases above already exit non-zero with a clean message on
stderr.
So this is not a proposal for a new convention. It is a proposal to
finish an existing one.
## Why now rather than later
contributing-docs/27_cli_implementation_guide.rst states that under
AIP-94 the existing `airflow` CLI remote commands stay in place but get
rewired internally to call the Public API. When `config get-value` is
rewired, it will inherit the API's 404 and stop exiting 0 regardless of
what we decide here.
That is really what I would like input on: this behaviour change is
already coming. Is it better to make it deliberately now, with a
newsfragment, in a small PR people can find -- or to let it arrive as a
side effect of the rewiring, where it is much easier to miss?
## What I would propose
1. `config get-value`: exit non-zero with a message on stderr when the
option does not exist, and keep stdout clean. (PR #72145, open.)
2. `dags state`: same treatment for the missing-DagRun branch, instead
of printing "None".
3. A newsfragment for both, since scripts may depend on the current
exit status.
4. Separately and cosmetically, `tasks states-for-dag-run` could raise
SystemExit rather than letting DagRunNotFound reach the user as a
traceback. Different problem, happy to leave it out of scope.
Note that public-airflow-interface.rst already says the CLI "behaviour
might change in details" and recommends the REST API for programmatic
use, so I do not think this needs a deprecation cycle -- but I would
rather hear that from the list than assume it.
Does aligning these two look right, and is doing it deliberately now
preferable to letting AIP-94 do it silently later?
Thanks,
Eason