Repository navigation
Conversation
1 task done
rjgoyln
force-pushed
the
fix/runtime-ti-readable-str
branch
2 times, most recently
from
September 17, 2026 13:15
3d9ab8b to
bee3249
Compare
rjgoyln
marked this pull request as ready for review
September 17, 2026 13:31
rjgoyln
requested review from
XD-DENG,
amoghrajesh,
ashb,
ephraimbuddy,
hussein-awala,
jedcunningham and
kaxil
as code owners
September 17, 2026 13:31
ashb
reviewed
Sep 25, 2026
This was referenced Sep 25, 2026
This was referenced Sep 25, 2026
rjgoyln
force-pushed
the
fix/runtime-ti-readable-str
branch
from
September 27, 2026 11:07
9918d30 to
8ad2d18
Compare
Contributor
Author
|
Thanks, all addressed. I’ve updated the state handling, removed the For the render test, I also switched to fixed |
rjgoyln
force-pushed
the
fix/runtime-ti-readable-str
branch
2 times, most recently
from
September 27, 2026 11:14
d6d4c05 to
8ad2d18
Compare
The default email subject renders {{ ti }}, which on Airflow 2 produced
the TaskInstance repr. On Airflow 3 the worker-side task instance is a
Pydantic model with no textual form of its own, so every field — UUIDs,
the task object, the bundle instance — lands in the subject line, and
operators can no longer tell at a glance which task failed.
Adapted from apache#67931 by Wilmer Dooley, whose PR went stale. The bundled body never named the Dag or the task, and the state field rendered the Python enum repr rather than the state itself. The heading is derived from the state so the template still reads correctly on the success and retry callbacks that share it.
Review follow-up. The parametrized test took over the tail of the defaults test, the state rationale was repeated in both templates, and the changed subject needs a note for anyone whose mail filters match on it.
The legacy email path never said which Dag or task had failed, and neither template carried the timestamps operators need to line the failure up against the rest of a run.
The Dag-processor callback path builds its task instance from the callback request alone, so it has no dates at all, and the Dag's Jinja environment is StrictUndefined -- a bare truth test on the attribute aborts the whole email.
The scheduler-side column is not nullable, but the Task SDK model declares map_index as optional and the surrounding code already guards for None, so mirroring the scheduler check alone would print "map_index=None".
The legacy path still put the task instance repr in the subject, UUID and all, which is what the issue reported; the two paths also disagreed on the shape of the subject and on whether the body named the state.
Airflow 3 has no mark-success endpoint, so mark_success_url returns log_url and the email offered the same destination twice under a label that promises something it cannot do. Folded in from apache#73271, which this supersedes.
Review follow-up: the new variable is usable from custom subject and content templates, so it belongs in the email configuration guide and the release note rather than appearing unexplained in an example.
Those emails are for tasks that never reached their own callbacks, and the callback request carries no state, so every one of them said the state was unknown -- while the request's email type is exactly the reason it fired.
Drop the subject prefix, report a missing state as the UI does, and set the Dag-processor state where the email type is already branched on. The templates are no longer compared verbatim in tests; the rendered output is.
Rebase adaptation: the Python 3.10 drop moved ruff's target version, and it now flags timezone.utc in favour of the alias.
rjgoyln
force-pushed
the
fix/runtime-ti-readable-str
branch
from
October 8, 2026 11:22
b52535a to
9635de5
Compare
This branch has not been deployed
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.
Summary
The default task failure email does not say what failed. Its subject renders
{{ ti }}, which on Airflow 2 gave theTaskInstancerepr and now dumps every field of a Pydantic model:Neither body names the Dag or the task; the notifier's bundled template renders
{{ ti.state }}, an enum whosestr()is its Python name; and both offer a "Mark success" link that goes to the log, since Airflow 3 aliasesmark_success_urltolog_url.[Airflow] <dag_id>.<task_id> <state> - Run <run_id>RuntimeTaskInstance.__str__mirrors the scheduler-sideTaskInstance.__repr__The default subject no longer interpolates
{{ ti }}, butsubject_templatefiles carried over from Airflow 2 do. It is__str__rather than__repr__so those read cleanly while a debugger still shows every field.Emails sent from the Dag processor are for tasks that never reached their own callbacks, and that request carries no state, so they take it from the email type instead.
The template work is adapted from #67931, stale since July, where the heading was hardcoded to a failure. #73271 is folded in here because it rewrites the same template blocks.
Behavior change
Both subject formats change;
providers/smtp/docs/changelog.rstcarries the note for anyone whose mail filters match on the notifier's.closes: #61667
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5) following the guidelines