Fix airflowctl connections test failing on stored connections - #73098
Merged
henry3260 merged 1 commit intoSep 13, 2026
Merged
Conversation
The API server fills the fields a test request leaves out from the stored connection, and decides which fields the caller meant to override from the keys present in the request body. Sending every unset field as an explicit null therefore reads as "clear these", so a stored host or port counts as changed and the request is refused; where it is not refused the stored credentials are overwritten with nulls and a blank connection gets tested. Nothing in the CLI can express an intentional null, so omitting them loses no caller intent.
Eason09053360
requested review from
bugraoz93,
dheerajturaga,
henry3260 and
potiuk
as code owners
September 13, 2026 17:21
justinpakzad
approved these changes
Sep 13, 2026
justinpakzad
left a comment
Contributor
There was a problem hiding this comment.
Thanks for the fix, looks good to me.
henry3260
approved these changes
Sep 13, 2026
Contributor
Backport failed to create: airflow-ctl/v0-1-test. View the failure log Run detailsNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
You can attempt to backport this manually by running: cherry_picker 65eb086 airflow-ctl/v0-1-testThis should apply the commit to the airflow-ctl/v0-1-test branch and leave the commit in conflict state marking After you have resolved the conflicts, you can continue the backport process by running: cherry_picker --continueIf you don't have cherry-picker installed, see the installation guide. |
1 task
xvega
pushed a commit
to xvega/airflow
that referenced
this pull request
Sep 13, 2026
…#73098) The API server fills the fields a test request leaves out from the stored connection, and decides which fields the caller meant to override from the keys present in the request body. Sending every unset field as an explicit null therefore reads as "clear these", so a stored host or port counts as changed and the request is refused; where it is not refused the stored credentials are overwritten with nulls and a blank connection gets tested. Nothing in the CLI can express an intentional null, so omitting them loses no caller intent. Co-authored-by: Eason09053360 <185830721+Eason09053360@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
airflowctl connections test --connection-id <id> --conn-type <type>is rejected for anyconnection that has a stored host or port:
The endpoint fills the fields the caller leaves out from the stored connection, and works out
which fields the caller meant to override from the keys present in the body —
model_fields_set(
routes/public/connections.py:387,services/public/connections.py:47). A key whose value isnullstill counts as present.The generated CLI builds
ConnectionBodyfrom a dict holding every field(
cli_config.py:858), so argparse'sNonefor each flag the user did not pass goes out as anexplicit
null. The server reads that as "clear these fields": the stored host reads as changed,no credentials were supplied, and the request is refused. On a connection with no host it is not
refused, but the stored login, password and extra are overwritten with
Noneand a blankconnection is tested instead.
ConnectionsOperations.createalready passesexclude_none=Truefor this reason, as do pools,backfills and asset events;
testwas missed.exclude_unset=Truewould be a no-op, since thecommand factory always populates every field. Nothing in the CLI can express an intentional
null, so dropping them loses no caller intent.What
ConnectionsOperations.testnow passesexclude_none=True.test_test_uses_schema_alias_in_request_bodyasserted the full body including the seven nulls,pinning the broken behaviour; it now expects the three keys actually set, matching
test_create_uses_schema_alias_in_request_body. Reverting the one-line fix fails it. The addedcomment records why the exact body matters beyond the alias, so the assertion is not loosened
back into the bug.
Left alone to keep this to one behaviour change:
updatehas the same root cause and is alreadycovered by #71333.
bulkhas it too, butexclude_none=Truewould only half-fix it — theconnections/variables/pools importcommands also pass hard-coded fallbacks such asdescription=v.get("description", ""), which are notNoneand would still overwrite storedvalues under
--action-on-existing-key overwrite. Fixing that means having those three commandssend only the keys present in the file.
Was generative AI tooling used to co-author this PR?