Skip to content

[v3-3-test] Fix task callbacks being skipped when TriggerDagRunOperator gets a 404 (#70719) - #71083

Merged
vatsrahul1001 merged 1 commit into
v3-3-testfrom
backport-f0c13dc-v3-3-test
Aug 4, 2026
Merged

[v3-3-test] Fix task callbacks being skipped when TriggerDagRunOperator gets a 404 (#70719)#71083
vatsrahul1001 merged 1 commit into
v3-3-testfrom
backport-f0c13dc-v3-3-test

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
  • Fix task callbacks being skipped when TriggerDagRunOperator gets a 404

run() maps a task's outcome through a flat chain of except clauses, and
several of those clauses do real work: they call the API server, or serialize
user-supplied values. Python does not offer an exception raised inside an
except clause to that clause's siblings, so when one of them raised, the
exception escaped run() entirely -- skipping the retry decision in
_handle_current_task_failed() and every callback, listener and failure email
in finalize().

The reported path: triggering a Dag that does not exist returns 404, which
DagRunOperations.trigger re-raises (it only special-cases the 409
already-exists case). The supervisor turns it into an API_SERVER_ERROR
response and CommsDecoder._from_frame raises AirflowRuntimeError -- from
inside except DagRunTriggerException, a few lines above the clause that
already handles AirflowRuntimeError. It is not limited to that path:
_defer_task and _await_input_task run serde_serialize over user-supplied
kwargs, which raises TypeError for any value serde has no serializer for.

Split the function at the point where deciding the outcome ends and reporting
it begins. _run_task_and_map_outcome() keeps the chain verbatim and returns
the outcome; run() calls it, and its except now covers the handlers too.
The chain and the terminal-state finally block are untouched, so this is a
behaviour change rather than a reshuffle of existing lines.

_handle_handler_failure() keeps the chain's own classifications instead of
routing everything through the retry-count check, so AirflowFailException,
AirflowSensorTimeout and AirflowTaskTerminated still fail without retrying
when they surface from a handler. It catches Exception, not BaseException,
so KeyboardInterrupt still reaches main()'s exit-code-2 path -- the
supervisor's default termination signal is SIGINT, so swallowing it would turn
an operator-initiated kill into an ordinary retry. If the failure path itself
raises, it fails closed on a plain FAILED state rather than re-entering the
code that just failed and escaping again.

  • Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI 175728472+Copilot@users.noreply.github.com


(cherry picked from commit f0c13dc)

Co-authored-by: Kaxil Naik kaxilnaik@gmail.com
Co-authored-by: Copilot Autofix powered by AI 175728472+Copilot@users.noreply.github.com

…tor` gets a 404 (#70719)

* Fix task callbacks being skipped when TriggerDagRunOperator gets a 404

`run()` maps a task's outcome through a flat chain of `except` clauses, and
several of those clauses do real work: they call the API server, or serialize
user-supplied values. Python does not offer an exception raised inside an
`except` clause to that clause's siblings, so when one of them raised, the
exception escaped `run()` entirely -- skipping the retry decision in
`_handle_current_task_failed()` and every callback, listener and failure email
in `finalize()`.

The reported path: triggering a Dag that does not exist returns 404, which
`DagRunOperations.trigger` re-raises (it only special-cases the 409
already-exists case). The supervisor turns it into an `API_SERVER_ERROR`
response and `CommsDecoder._from_frame` raises `AirflowRuntimeError` -- from
inside `except DagRunTriggerException`, a few lines above the clause that
already handles `AirflowRuntimeError`. It is not limited to that path:
`_defer_task` and `_await_input_task` run `serde_serialize` over user-supplied
kwargs, which raises `TypeError` for any value serde has no serializer for.

Split the function at the point where deciding the outcome ends and reporting
it begins. `_run_task_and_map_outcome()` keeps the chain verbatim and returns
the outcome; `run()` calls it, and its `except` now covers the handlers too.
The chain and the terminal-state `finally` block are untouched, so this is a
behaviour change rather than a reshuffle of existing lines.

`_handle_handler_failure()` keeps the chain's own classifications instead of
routing everything through the retry-count check, so `AirflowFailException`,
`AirflowSensorTimeout` and `AirflowTaskTerminated` still fail without retrying
when they surface from a handler. It catches `Exception`, not `BaseException`,
so `KeyboardInterrupt` still reaches `main()`'s exit-code-2 path -- the
supervisor's default termination signal is SIGINT, so swallowing it would turn
an operator-initiated kill into an ordinary retry. If the failure path itself
raises, it fails closed on a plain FAILED state rather than re-entering the
code that just failed and escaping again.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------
(cherry picked from commit f0c13dc)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@vatsrahul1001
vatsrahul1001 marked this pull request as ready for review August 4, 2026 12:56
@vatsrahul1001 vatsrahul1001 added this to the Airflow 3.3.1 milestone Aug 4, 2026
@vatsrahul1001 vatsrahul1001 added the type:bug-fix Changelog: Bug Fixes label Aug 4, 2026
@vatsrahul1001
vatsrahul1001 merged commit 4e8a1d4 into v3-3-test Aug 4, 2026
117 of 126 checks passed
@vatsrahul1001
vatsrahul1001 deleted the backport-f0c13dc-v3-3-test branch August 4, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:task-sdk type:bug-fix Changelog: Bug Fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants