Unhandled AttributeError in BranchDayOfWeekOperator and BranchDateTimeOperator when use_task_logical_date=True without dag_run
- Dominant language
- Python
- Stars
- 46.9k
- Forks
- 17.8k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 472
Description
### Apache Airflow version
3.0.0 (main branch)
### What happened?
When running `BranchDayOfWeekOperator` or `BranchDateTimeOperator` with `use_task_logical_date=True` in execution contexts where `context.get("dag_run")` returns `None` (for instance during standalone task execution, custom execution contexts, or unit tests), the task crashes with an unhandled `AttributeError`:
```text
AttributeError: 'NoneType' object has no attribute 'run_after'
```
Looking at `airflow/providers/standard/operators/weekday.py`:
```python
if self.use_task_logical_date:
now = context.get("logical_date")
if not now:
dag_run = context.get("dag_run")
now = dag_run.run_after # type: ignore[union-attr, assignment]
```
When `logical_date` is `None` and `dag_run` is also `None`, accessing `dag_run.run_after` causes an immediate `AttributeError`.
### What you think should happen instead?
The operator should check whether `dag_run` exists before attempting to access `.run_after`, and raise a clear `AirflowException` or `ValueError` if neither `logical_date` nor `dag_run.run_after` can be determined.
For comparison, `DayOfWeekSensor` in `airflow/providers/standard/sensors/weekday.py` handles this scenario safely:
```python
if self.use_task_logical_date:
logical_date = context.get("logical_date")
dag_run = context.get("dag_run")
if not (logical_date or (dag_run and dag_run.run_after)):
raise ValueError(
"Either `logical_date` or `run_after` should be provided in the task context when "
"`use_task_logical_date` is True"
)
```
`BranchDayOfWeekOperator` and `BranchDateTimeOperator` should align with this defensive pattern.
### How to reproduce
Call `choose_branch` on `BranchDayOfWeekOperator` with `use_task_logical_date=True` using a context missing `logical_date` and `dag_run`:
```python
from airflow.providers.standard.operators.weekday import BranchDayOfWeekOperator
op = BranchDayOfWeekOperator(
task_id="test_branch",
follow_task_ids_if_true="true_task",
follow_task_ids_if_false="false_task",
week_day="Monday",
use_task_logical_date=True,
)
# Context without logical_date or dag_run
op.choose_branch(context={})
```
### Anything else?
This issue occurs in both:
- `airflow/providers/standard/operators/weekday.py` (`BranchDayOfWeekOperator`)
- `airflow/providers/standard/operators/datetime.py` (`BranchDateTimeOperator`)
### Are you willing to submit PR?
- [ ] Yes I am willing to submit a PR!
Contributor guide
Research direction
Start with choose_branch in airflow/providers/standard/operators/weekday.py and the corresponding logic in airflow/providers/standard/operators/datetime.py, then compare the defensive handling in airflow/providers/standard/sensors/weekday.py. Reproduce the missing-logical-date and missing-dag-run context described in the issue, and consider the work done when both operators raise a clear exception instead of AttributeError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100