Skip to content

Avoid parsing templated DateTimeSensorAsync targets at Dag parse time - #72659

Merged
potiuk merged 2 commits into
apache:mainfrom
SIBTAIN-ASAD:fix-datetime-sensor-templated-trigger
Sep 20, 2026
Merged

potiuk merged 2 commits into
apache:mainfrom
SIBTAIN-ASAD:fix-datetime-sensor-templated-trigger

Conversation

@SIBTAIN-ASAD

Copy link
Copy Markdown
Contributor

Why

DateTimeSensorAsync can be configured with start_from_trigger=True, but templated target_time values are rendered after Dag parsing. Calling _moment in __init__ therefore parses the raw Jinja expression and crashes the Dag.

What changed

Keep triggerer-start for concrete targets, but fall back to the normal worker path when target_time contains a Jinja template. The worker path resolves the rendered datetime before constructing DateTimeTrigger.

Fixes #70284

Verification

  • uv run --project providers/standard pytest providers/standard/tests/unit/standard/sensors/test_date_time.py -xvs (16 passed)
  • uvx prek run --stage pre-commit --files providers/standard/src/airflow/providers/standard/sensors/date_time.py providers/standard/tests/unit/standard/sensors/test_date_time.py

@boring-cyborg

boring-cyborg Bot commented Sep 7, 2026

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our prek-hooks will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example Dag that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
  • Always keep your Pull Requests rebased, otherwise your build might fail due to changes not related to your commits.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

SIBTAIN-ASAD and others added 2 commits September 20, 2026 20:16
Prevent templated targets from crashing Dag parsing when triggerer-start is requested. The value is rendered only after parsing, so it must be resolved before the trigger is constructed.
…er args

A Dag author who asks for start_from_trigger=True with a templated target_time
now silently gets the worker path, so say so on the parameter. The extra
assertion pins the other half of the guard: the class-level start_trigger_args
must be left alone rather than replaced with a copy built from the raw template.

Generated-by: Claude Opus 5
@potiuk
potiuk force-pushed the fix-datetime-sensor-templated-trigger branch from 319c554 to 24ce45d Compare September 20, 2026 18:17

@potiuk potiuk 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.

The guard correctly stops DateTimeSensorAsync.__init__ from parsing a Jinja target_time at Dag-parse time and falls back to the worker path, where execute() resolves the rendered datetime before constructing DateTimeTrigger. That is in line with the earlier decision that the triggerer must not render templates itself, and the regression test does fail without the fix.

I pushed a small fixup on top and rebased the branch on main:

  • :param start_from_trigger: now says it is ignored when target_time is a Jinja template. Without that, a Dag author who asked for triggerer-start has no way to find out why their task went through a worker.
  • The test also asserts op.start_trigger_args is DateTimeSensorAsync.start_trigger_args, pinning the other half of the guard — the class attribute must be left alone rather than replaced with a copy built from the raw template. That complements test_start_trigger_args_are_not_shared_between_tasks.

Smaller observations

  • The hard-coded {{ / {% / {# check will not recognise custom delimiters set through DAG(jinja_environment_kwargs=...). That matches how core already detects templates in airflow.utils.helpers.parse_template_string, so it is fine as is — just noting the parse-time crash still exists for that rare configuration.
  • Mapped tasks built with partial(start_from_trigger=True).expand(target_time=[...]) skip __init__, so the guard does not run on that path. That is pre-existing and documented, not something this PR regresses.
  • The PR description does not include the template's "Was generative AI tooling used to co-author this PR?" section. Could you restore it and answer it either way? See contributing-docs/05_pull_requests.rst.

This review was drafted by an AI-assisted tool and
confirmed by an Apache Airflow maintainer. The maintainer
approving this PR has read the findings and signed off. If
something feels off, please reply on the PR and a maintainer
will follow up.

More on how Apache Airflow handles maintainer review:
contributing-docs/05_pull_requests.rst.

@potiuk
potiuk merged commit 259ed86 into apache:main Sep 20, 2026
2 checks passed
@boring-cyborg

boring-cyborg Bot commented Sep 20, 2026

Copy link
Copy Markdown

Awesome work, congrats on your first merged pull request! You are invited to check our Issue Tracker for additional contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DateTimeSensorAsync crashes Dag parsing with templated target_time + start_from_trigger=True

2 participants