Skip to content

Migrate Task SDK to httpx2 - #73116

Merged
hussein-awala merged 19 commits into
apache:mainfrom
DataDog:zach.gottesman/task-sdk-httpx2
Oct 14, 2026
Merged

hussein-awala merged 19 commits into
apache:mainfrom
DataDog:zach.gottesman/task-sdk-httpx2

Conversation

@zach-overflow

@zach-overflow zach-overflow commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

What?

  • Modifies apache-airflow-task-sdk's dependency on httpx → httpx2. The Execution API Client is now an httpx2.Client.
  • Adds truststore as an explicit task-sdk dependency — replacing the previously used certifi which was previously implicitly installed viahttpx, but httpx2 depends on truststore instead. Details for this noted in news-fragment.
  • Moves InProcessExecutionAPI.transport / .atransport in airflow-core to httpx2, plus the call sites that build or drive them. Objects don't cross the httpx/httpx2 boundary, and the only consumers of those transports are Task SDK clients. This adds httpx2 as an airflow-core runtime dependency; the rest of airflow-core stays on httpx.
  • Makes devel-common's in-process task-run helpers resolve the HTTP stack from the installed Task SDK Client rather than hardcoding one. Compat jobs pair this repo's devel-common with a released Airflow whose SDK is still on httpx, and handing such a client an httpx2 transport trips httpx's own stream-type assertion.
  • Makes shared/logging to suppress and mute both stacks, since airflow-core and the Task SDK are now on different ones.
  • Adds an ast-grep pre-commit check to prevent re-introducing httpx in the Task SDK, mirroring the providers one.

Why?


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)
  • Generated-by: Claude Code (Opus 5) following the guidelines
  • Scope of AI use:
    • I pointed Claude Code at the task-sdk httpx usage and it did the import replacements and dependency updates.
    • It traced the cross-package boundary (in-process Execution API transports, devel-common test helpers, prek scripts) and migrated those call sites, then made the devel-common helpers stack-agnostic after the compat jobs caught the released-SDK case.
    • It wrote the ast-grep rule and verified it fires.
    • I reviewed the diff and wrote the PR description.

@zach-overflow
zach-overflow force-pushed the zach.gottesman/task-sdk-httpx2 branch 2 times, most recently from a6203f6 to 388ad9a Compare September 16, 2026 08:37

@amoghrajesh amoghrajesh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good reason to support httpx2 since httpx is not actively maintained, most are nits, but the compat concern needs addressing.

Comment thread task-sdk/src/airflow/sdk/api/client.py Resolved
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

uv.lock on main just moved via #74559 ("Mark the Tinkerpop and Vespa providers as unavailable on Python 3.14"), commit 0f06fca and this PR currently conflicts.

Quickest fix:

git fetch upstream main && git rebase upstream/main
rm uv.lock && uv lock
git add uv.lock && git rebase --continue
git push --force-with-lease

Automated nudge — ignore if you're not ready to rebase. This comment is updated in place on future uv.lock bumps.

@zach-overflow
zach-overflow force-pushed the zach.gottesman/task-sdk-httpx2 branch 2 times, most recently from 4e1b42c to 0c83ff2 Compare September 28, 2026 13:30
@zach-overflow
zach-overflow force-pushed the zach.gottesman/task-sdk-httpx2 branch from 0c83ff2 to 87852a1 Compare October 1, 2026 13:23
@kaxil kaxil mentioned this pull request Oct 1, 2026
5 of 7 tasks
@zach-overflow
zach-overflow force-pushed the zach.gottesman/task-sdk-httpx2 branch from 87852a1 to c992360 Compare October 2, 2026 13:42
zach-overflow and others added 13 commits October 13, 2026 09:02
Both HTTP stacks can coexist while compatibility jobs use older SDK
distributions. The migration needs regression coverage for its logging
behavior without exposing development-only helpers as public APIs.
Tests added on main for in-process shutdown still referenced httpx, which this branch no longer imports in the module.
httpx2 verifies against the system trust store via truststore, so keeping certifi for the Execution API client would add a direct dependency only to maintain a second, different set of trusted roots in the same worker.
Ruff already enforces banned imports, so a separate ast-grep hook and its extra pre-commit dependency are unnecessary. extend-banned-api adds to the root banned-api table instead of replacing it.
The test arrived on main after the Task SDK moved to httpx2 and still referenced httpx, which the module no longer imports.
Mocking load_verify_locations while also writing a CA file to disk tested neither path convincingly. Keeping the certificate-generation imports inside the fixture limits them to the one place that needs them.
Co-authored-by: Ash Berlin-Taylor <ash_github@firemirror.com>
The helper arrived on main after the Task SDK moved to httpx2 and still referenced httpx, which the module no longer imports.
The test arrived on main after the Task SDK moved to httpx2 and still referenced httpx, which the module no longer imports.
The tests arrived on main after the Task SDK moved to httpx2; the client rejects httpx transports.
@zach-overflow
zach-overflow force-pushed the zach.gottesman/task-sdk-httpx2 branch from c43ea9f to b312d3d Compare October 13, 2026 13:24

@hussein-awala hussein-awala left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, LGTM

@hussein-awala
hussein-awala merged commit 63f5845 into apache:main Oct 14, 2026
127 checks passed
@hussein-awala hussein-awala added the type:misc/internal Changelog: Misc changes that should appear in change log label Oct 14, 2026
@hussein-awala hussein-awala added this to the Airflow 3.4.0 milestone Oct 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Backport successfully created: v3-4-test

Note: As of Merging PRs targeted for Airflow 3.X
the committer who merges the PR is responsible for backporting the PRs that are bug fixes (generally speaking) to the maintenance branches.

In matter of doubt please ask in #release-management Slack channel.

Status Branch Result
✅ v3-4-test PR Link

ashb pushed a commit that referenced this pull request Oct 16, 2026
rjgoyln added a commit to rjgoyln/airflow that referenced this pull request Oct 23, 2026
The Task SDK moved from httpx to httpx2 (apache#73116) after this branch was
written, so the rebased helper and its tests referred to a module that
is no longer imported there.
henry3260 added a commit that referenced this pull request Oct 25, 2026
* Fix airflowctl tracebacks on JSON errors behind a reverse proxy

airflowctl compared the error response content-type against the exact
string "application/json". Any reverse proxy, ingress, or API gateway
that returns "application/json; charset=utf-8" — or emits its own
"application/problem+json" error — fell outside that comparison, so
ServerResponseError was never constructed and the friendly "not found"
messages in the dags and tasks commands were skipped. The bare
httpx.HTTPStatusError raised instead is not handled by
safe_call_command, so users saw a raw traceback. Airflow's own API
server does not send a charset, which is why this only surfaces once
something sits in front of it.

Media types are case-insensitive and may carry parameters (RFC 9110),
so the header has to be parsed rather than compared whole.

Matching more responses also routes bodies into the error path that are
valid JSON but not objects, which dict() rejected with a ValueError from
that same unprotected path, and bodies that do not decode at all.

* Move media type rationale from docstring into an inline comment

* Apply the same JSON media type handling to the Task SDK client

The Task SDK client carries the identical exact-string content-type
comparison, so a task talking to the API server through a proxy that
declares a charset loses the server's error detail and, because the
raised exception is then a plain httpx.HTTPStatusError, no longer hits
the status-specific handling in the supervisor and the task runner.

* Cross-reference the twin JSON media type checks

The airflowctl and Task SDK copies are the same three lines with
different comments, and they already drifted in the commits that
created them. A pointer in each makes the next person notice there
are two.

* Add newsfragment for the API client error handling fix

Requested during review: the Task SDK half of the change ships in
airflow-core, and both effects are visible to users running behind a
proxy.

* Use httpx2 in the Task SDK JSON media type check

The Task SDK moved from httpx to httpx2 (#73116) after this branch was
written, so the rebased helper and its tests referred to a module that
is no longer imported there.

* Describe the airflowctl symptom as it is on main now

Since #73307 airflowctl catches the bare HTTPStatusError and prints one
line instead of a traceback, so the newsfragment overstated it; the
server's own message is still what gets lost.

* Keep only the airflowctl test cases the fix changes

The bare media type and the 404/500 axis repeat what
test_error_parsing_with_unread_body already covers, and dict() of an
object body worked before; none of them fail without the fix.

* Explain the non-object log guard by what it protects

The previous comment described the dict() call the guard replaced,
which is no longer in the code.

* Limit the newsfragment to the Task SDK fix

airflow-core's release notes ship only the Task SDK side; airflowctl's
changelog is built from git log. The task runner never handled
ServerResponseError, so it is no longer named.

* Rename the newsfragment to this PR's number

* Shorten the media type comments

The longer versions restated what the diff and the PR already explain,
and the two _has_json_body copies now carry the same note.

---------

Co-authored-by: Henry Chen <henrychen@apache.org>
potiuk pushed a commit that referenced this pull request Oct 25, 2026
…reverse proxy (#75493) (#75622)

* Fix airflowctl tracebacks on JSON errors behind a reverse proxy

airflowctl compared the error response content-type against the exact
string "application/json". Any reverse proxy, ingress, or API gateway
that returns "application/json; charset=utf-8" — or emits its own
"application/problem+json" error — fell outside that comparison, so
ServerResponseError was never constructed and the friendly "not found"
messages in the dags and tasks commands were skipped. The bare
httpx.HTTPStatusError raised instead is not handled by
safe_call_command, so users saw a raw traceback. Airflow's own API
server does not send a charset, which is why this only surfaces once
something sits in front of it.

Media types are case-insensitive and may carry parameters (RFC 9110),
so the header has to be parsed rather than compared whole.

Matching more responses also routes bodies into the error path that are
valid JSON but not objects, which dict() rejected with a ValueError from
that same unprotected path, and bodies that do not decode at all.

* Move media type rationale from docstring into an inline comment

* Apply the same JSON media type handling to the Task SDK client

The Task SDK client carries the identical exact-string content-type
comparison, so a task talking to the API server through a proxy that
declares a charset loses the server's error detail and, because the
raised exception is then a plain httpx.HTTPStatusError, no longer hits
the status-specific handling in the supervisor and the task runner.

* Cross-reference the twin JSON media type checks

The airflowctl and Task SDK copies are the same three lines with
different comments, and they already drifted in the commits that
created them. A pointer in each makes the next person notice there
are two.

* Add newsfragment for the API client error handling fix

Requested during review: the Task SDK half of the change ships in
airflow-core, and both effects are visible to users running behind a
proxy.

* Use httpx2 in the Task SDK JSON media type check

The Task SDK moved from httpx to httpx2 (#73116) after this branch was
written, so the rebased helper and its tests referred to a module that
is no longer imported there.

* Describe the airflowctl symptom as it is on main now

Since #73307 airflowctl catches the bare HTTPStatusError and prints one
line instead of a traceback, so the newsfragment overstated it; the
server's own message is still what gets lost.

* Keep only the airflowctl test cases the fix changes

The bare media type and the 404/500 axis repeat what
test_error_parsing_with_unread_body already covers, and dict() of an
object body worked before; none of them fail without the fix.

* Explain the non-object log guard by what it protects

The previous comment described the dict() call the guard replaced,
which is no longer in the code.

* Limit the newsfragment to the Task SDK fix

airflow-core's release notes ship only the Task SDK side; airflowctl's
changelog is built from git log. The task runner never handled
ServerResponseError, so it is no longer named.

* Rename the newsfragment to this PR's number

* Shorten the media type comments

The longer versions restated what the diff and the PR already explain,
and the two _has_json_body copies now carry the same note.

---------
(cherry picked from commit 352ca60)

Co-authored-by: rjgoyln <151457491+rjgoyln@users.noreply.github.com>
Co-authored-by: Henry Chen <henrychen@apache.org>
@kaxil kaxil mentioned this pull request Nov 4, 2026
1 task done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:API Airflow's REST/HTTP API area:dev-tools area:logging area:task-sdk kind:documentation type:misc/internal Changelog: Misc changes that should appear in change log

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants