Skip to content

Commit 1e0ca1e

Browse files
[v3-3-test] Fix 500 when combining last-run and any-run Dag state filters (#71366) (#71371)
(cherry picked from commit 7cdb9ad) Co-authored-by: Rahul Vats <43964496+vatsrahul1001@users.noreply.github.com>
1 parent a10047a commit 1e0ca1e

2 files changed

Lines changed: 25 additions & 3 deletions

File tree

airflow-core/src/airflow/api_fastapi/common/parameters.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from sqlalchemy import Column, String, and_, func, not_, or_, select as sql_select, true as sql_true
3939
from sqlalchemy.ext.compiler import compiles
4040
from sqlalchemy.inspection import inspect
41+
from sqlalchemy.orm import aliased
4142
from sqlalchemy.sql.functions import FunctionElement
4243

4344
from airflow._shared.timezones import timezone
@@ -1279,10 +1280,13 @@ def to_orm(self, select: Select) -> Select:
12791280
if self.value is None and self.skip_none:
12801281
return select
12811282

1282-
# EXISTS resolves each Dag via the (dag_id, state) index instead of scanning every run in the state.
1283+
# Alias DagRun so this EXISTS subquery cannot auto-correlate to a DagRun the outer query
1284+
# may already reference (e.g. the last_dag_run_state filter), which would strip the
1285+
# subquery's FROM and raise. EXISTS resolves each Dag via the (dag_id, state) index.
1286+
any_run = aliased(DagRun)
12831287
has_run_in_state = (
1284-
sql_select(DagRun.dag_id)
1285-
.where(DagRun.dag_id == DagModel.dag_id, DagRun.state == self.value)
1288+
sql_select(any_run.dag_id)
1289+
.where(any_run.dag_id == DagModel.dag_id, any_run.state == self.value)
12861290
.exists()
12871291
)
12881292
return select.where(has_run_in_state)

airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_dags.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,24 @@ def test_dag_run_state_matches_any_run_not_only_latest(self, test_client, sessio
160160
assert any_state.status_code == 200
161161
assert [dag["dag_id"] for dag in any_state.json()["dags"]] == [DAG1_ID]
162162

163+
@pytest.mark.usefixtures("configure_git_connection_for_dag_bundle")
164+
def test_last_and_any_run_state_filters_combined(self, test_client, session):
165+
# Regression: combining the last-run and any-run state filters must return the
166+
# intersection, not raise. The any-run EXISTS subquery must not correlate to the
167+
# DagRun the last-run filter joins into the outer query.
168+
latest_run = session.scalar(
169+
select(DagRun).where(DagRun.dag_id == DAG1_ID, DagRun.run_id == "run_id_5")
170+
)
171+
latest_run.state = DagRunState.FAILED
172+
session.commit()
173+
174+
response = test_client.get(
175+
"/dags",
176+
params={"last_dag_run_state": "failed", "dag_run_state": "failed", "dag_ids": [DAG1_ID]},
177+
)
178+
assert response.status_code == 200
179+
assert [dag["dag_id"] for dag in response.json()["dags"]] == [DAG1_ID]
180+
163181
@pytest.fixture
164182
def setup_hitl_data(self, create_task_instance: TaskInstance, session: Session):
165183
"""Setup HITL test data for parametrized tests."""

0 commit comments

Comments
 (0)