From f37e451ca32a8d10c2826d32a931dcdaa5c8bff3 Mon Sep 17 00:00:00 2001 From: vincbeck Date: Tue, 16 Jun 2026 14:08:14 -0400 Subject: [PATCH] Fix triggerer crash when trigger subclass does not call `super().__init__()` --- airflow-core/src/airflow/triggers/base.py | 4 ++-- .../tests/unit/triggers/test_base_trigger.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/airflow-core/src/airflow/triggers/base.py b/airflow-core/src/airflow/triggers/base.py index 6f6061e3366f8..f587fd8de3ff4 100644 --- a/airflow-core/src/airflow/triggers/base.py +++ b/airflow-core/src/airflow/triggers/base.py @@ -101,8 +101,8 @@ def task(self) -> Operator | None: return None @property - def task_instance(self) -> TaskInstance: - return self._task_instance + def task_instance(self) -> TaskInstance | None: + return getattr(self, "_task_instance", None) @task_instance.setter def task_instance(self, value: TaskInstance | None) -> None: diff --git a/airflow-core/tests/unit/triggers/test_base_trigger.py b/airflow-core/tests/unit/triggers/test_base_trigger.py index 5f32cb23bfe41..429e54615293a 100644 --- a/airflow-core/tests/unit/triggers/test_base_trigger.py +++ b/airflow-core/tests/unit/triggers/test_base_trigger.py @@ -140,6 +140,25 @@ def test_render_template_fields_empty_when_no_trigger_kwargs(create_task_instanc assert trigger.name == "Hello {{ name }}" +class _TriggerWithoutSuperInit(BaseTrigger): + """A trigger that does not call super().__init__() — simulates third-party triggers.""" + + def __init__(self, queue_url: str): + self.queue_url = queue_url + + def serialize(self): + return (f"{type(self).__module__}.{type(self).__qualname__}", {"queue_url": self.queue_url}) + + async def run(self): + yield TriggerEvent({"queue_url": self.queue_url}) + + +def test_task_instance_property_works_without_super_init(): + """task_instance property must return None when subclass skips super().__init__().""" + trigger = _TriggerWithoutSuperInit(queue_url="https://sqs.example.com/queue") + assert trigger.task_instance is None + + class _PlainEventTrigger(BaseEventTrigger): """A BaseEventTrigger that does not opt into shared streams."""