apache / apache/airflow

Unhandled AttributeError in BranchDayOfWeekOperator and BranchDateTimeOperator when use_task_logical_date=True without dag_run

Open
#72,031 0 comments 0 reactions 0 assignees View on GitHub
area:providers kind:bug provider:standard
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.