diff --git a/airflow-core/src/airflow/cli/commands/config_command.py b/airflow-core/src/airflow/cli/commands/config_command.py index 77b187b589991..a183297efad1b 100644 --- a/airflow-core/src/airflow/cli/commands/config_command.py +++ b/airflow-core/src/airflow/cli/commands/config_command.py @@ -74,11 +74,15 @@ def get_value(args): # providers are initialized. Theoretically Providers might add new sections and options # but also override defaults for existing options, so without loading all providers we # cannot be sure what is the final value of the option. - try: - value = conf.get(args.section, args.option) - print(value) - except AirflowConfigException: - pass + + # Neither `except AirflowConfigException` (also swallows a failed `*_cmd` or an unreachable + # secrets backend) nor a `has_option()` pre-check (re-emits a deprecated option's warning, + # https://github.com/apache/airflow/issues/40319) works here. `fallback=None` also returns + # before conf.get() logs "not found" to stdout, which get-value must keep clean. + value = conf.get(args.section, args.option, fallback=None) + if value is None: + raise SystemExit(f"The option [{args.section}/{args.option}] is not found in config.") + print(value) class ConfigParameter(NamedTuple): diff --git a/airflow-core/tests/unit/cli/commands/test_config_command.py b/airflow-core/tests/unit/cli/commands/test_config_command.py index 3e3913d694720..ee9ec846baf1c 100644 --- a/airflow-core/tests/unit/cli/commands/test_config_command.py +++ b/airflow-core/tests/unit/cli/commands/test_config_command.py @@ -27,6 +27,7 @@ from airflow.cli.commands import config_command from airflow.cli.commands.config_command import ConfigChange, ConfigParameter from airflow.configuration import conf +from airflow.exceptions import AirflowConfigException from tests_common.test_utils.config import conf_vars @@ -263,11 +264,19 @@ def test_should_not_raise_exception_when_section_for_config_with_value_defined_e config_command.get_value(self.parser.parse_args(["config", "get-value", "some_section", "value"])) - def test_should_raise_exception_when_option_is_missing(self, caplog): - config_command.get_value( - self.parser.parse_args(["config", "get-value", "missing-section", "dags_folder"]) - ) - assert "section/key [missing-section/dags_folder] not found in config" in caplog.text + def test_should_raise_exception_when_option_is_missing(self): + with pytest.raises(SystemExit) as ctx: + config_command.get_value( + self.parser.parse_args(["config", "get-value", "missing-section", "dags_folder"]) + ) + assert str(ctx.value) == "The option [missing-section/dags_folder] is not found in config." + + @conf_vars({("core", "asset_manager_kwargs_cmd"): "false"}) + def test_should_not_report_a_failed_lookup_as_a_missing_option(self): + with pytest.raises(AirflowConfigException, match="Cannot execute false"): + config_command.get_value( + self.parser.parse_args(["config", "get-value", "core", "asset_manager_kwargs"]) + ) class TestConfigLint: