apache / apache/airflow

I am upgrading from Airflow 2.11.0 to Airflow 3.1.6 and noticed a change in behavior regarding the `ExternalTaskMarker`

Open
#61,451 3 comments 1 reaction 1 assignee Claimed by @jroachgolf84 View on GitHub
area:core kind:bug priority:upgrade_to_airflow3
Dominant language
Python
Stars
46.9k
Forks
17.8k
Avg merge
2d 9h
Merged PRs (30d)
472

Description

I am upgrading from Airflow 2.11.0 to Airflow 3.1.6 and noticed a change in behavior regarding the `ExternalTaskMarker ` or maybe I am just using Airflow 3.1.6 wrong, so any help counts.

In Airflow 2.11.0, when I cleared a task upstream of an `ExternalTaskMarker `(and selected the "Recursive" or "Downstream" clearing options), the corresponding ExternalTaskSensor in the child DAG would also be cleared. In Airflow 3, this relationship seems broken; clearing the parent task does not trigger a clear on the child task.

We want to maintain task-level cross-DAG dependencies. While we are aware of the new Assets feature in Airflow 3, we specifically need the granular control provided by `ExternalTaskMarker` to ensure that re-running a specific parent task forces the child sensor to reset.

**Environment**:
Airflow Version: 3.0.x
Executor: CeleryExecutor
Python Version: 3.12
Ran on docker container setup locally

Minimal working example:

```
# --- PARENT DAG ---
from datetime import datetime
from airflow import DAG
from airflow.operators.bash import BashOperator
from airflow.sensors.external_task import ExternalTaskMarker

with DAG(
dag_id='parent_dag',
start_date=datetime(2026, 1, 18),
schedule='@daily',
catchup=False
) as parent_dag:

task_1 = BashOperator(
task_id='echo_hello',
bash_command='echo HELLO!!!!'
)

# Marker to point to child_dag/receive_call
parent_trigger = ExternalTaskMarker(
task_id='parent_trigger',
external_dag_id='child_dag',
external_task_id='receive_call'
)

task_1 >> parent_trigger

# --- CHILD DAG ---
from airflow.sensors.external_task import ExternalTaskSensor

with DAG(
dag_id='child_dag',
start_date=datetime(2026, 1, 18),
schedule='@daily',
catchup=False
) as child_dag:

receive_call = ExternalTaskSensor(
task_id='receive_call',
external_dag_id='parent_dag',
external_task_id='parent_trigger'
)

child_task = BashOperator(
task_id='child_echo',
bash_command='echo DONE'
)

receive_call >> child_task
```

_Originally posted by @LinasData in https://github.com/apache/airflow/discussions/60905_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.