This is an automated email from the ASF dual-hosted git repository.

vatsrahul1001 pushed a commit to branch v3-4-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-4-test by this push:
     new 79e1aea617c [v3-4-test] Reject non-positive max_active_runs when 
creating a backfill (#75071) (#75320)
79e1aea617c is described below

commit 79e1aea617c6ea237a115f7aa9666fb9fdab29de
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sat Oct 24 14:36:50 2026 +0000

    [v3-4-test] Reject non-positive max_active_runs when creating a backfill 
(#75071) (#75320)
    
    POST /api/v2/backfills accepted max_active_runs of 0 or below and
    created the backfill. The scheduler only starts a backfill run while
    the number of running runs is below max_active_runs, so with 0 or a
    negative value every run stayed queued forever. The dry-run endpoint
    shares the same body and accepted it as well.
    
    The legacy `airflow backfill create --max-active-runs` already rejects
    these values with positive_int(allow_zero=False), and the UI backfill
    form sets min=1. BackfillPostBody now requires max_active_runs >= 1, so
    the API returns 422 instead.
    (cherry picked from commit 7d94a66507ed1085f2e9773453e6fd355aa0bd77)
    
    Co-authored-by: W. H. Wang <[email protected]>
---
 .../api_fastapi/core_api/datamodels/backfills.py   |  2 +-
 .../core_api/openapi/v2-rest-api-generated.yaml    |  1 +
 .../airflow/ui/openapi-gen/requests/schemas.gen.ts |  1 +
 .../core_api/routes/public/test_backfills.py       | 28 ++++++++++++++++++++++
 .../src/airflowctl/api/datamodels/generated.py     |  2 +-
 5 files changed, 32 insertions(+), 2 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/backfills.py 
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/backfills.py
index 3833825479d..808815da72a 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/backfills.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/backfills.py
@@ -37,7 +37,7 @@ class BackfillPostBody(StrictBaseModel):
     run_backwards: bool = False
     dag_run_conf: dict | None = None
     reprocess_behavior: ReprocessBehavior = ReprocessBehavior.NONE
-    max_active_runs: int = 10
+    max_active_runs: int = Field(default=10, ge=1)
     run_on_latest_version: bool | None = Field(
         default=None,
         description="Run on the latest bundle version of the Dag for each 
backfilled run. "
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
index 057fdbc91b4..aecd0bdeaf0 100644
--- 
a/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
+++ 
b/airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml
@@ -13082,6 +13082,7 @@ components:
           default: none
         max_active_runs:
           type: integer
+          minimum: 1.0
           title: Max Active Runs
           default: 10
         run_on_latest_version:
diff --git a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts 
b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
index d95a83b65db..ccbdf81c024 100644
--- a/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
+++ b/airflow-core/src/airflow/ui/openapi-gen/requests/schemas.gen.ts
@@ -985,6 +985,7 @@ export const $BackfillPostBody = {
         },
         max_active_runs: {
             type: 'integer',
+            minimum: 1,
             title: 'Max Active Runs',
             default: 10
         },
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py
index 5c852117c1d..926d5271fbe 100644
--- 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py
+++ 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py
@@ -576,6 +576,20 @@ class TestCreateBackfill(TestBackfillEndpoint):
         assert response.status_code == 404
         assert response.json().get("detail") == "Could not find dag 
DAG_NOT_EXIST"
 
+    @pytest.mark.parametrize("max_active_runs", [0, -3])
+    def test_create_backfill_rejects_non_positive_max_active_runs(self, 
max_active_runs, test_client):
+        response = test_client.post(
+            url="/backfills",
+            json={
+                "dag_id": "TEST_DAG_1",
+                "from_date": "2024-01-01T00:00:00Z",
+                "to_date": "2024-01-02T00:00:00Z",
+                "max_active_runs": max_active_runs,
+            },
+        )
+        assert response.status_code == 422
+        assert response.json()["detail"][0]["loc"] == ["body", 
"max_active_runs"]
+
     def test_no_schedule_dag(self, session, dag_maker, test_client):
         with dag_maker(session=session, dag_id="TEST_DAG_1", schedule=None) as 
dag:
             EmptyOperator(task_id="mytask")
@@ -1330,6 +1344,20 @@ class TestCreateBackfillDryRun(TestBackfillEndpoint):
         assert response.status_code == 422
         assert "Invalid input for param validated_number" in 
response.json().get("detail")
 
+    @pytest.mark.parametrize("max_active_runs", [0, -3])
+    def 
test_create_backfill_dry_run_rejects_non_positive_max_active_runs(self, 
max_active_runs, test_client):
+        response = test_client.post(
+            url="/backfills/dry_run",
+            json={
+                "dag_id": "TEST_DAG_1",
+                "from_date": "2024-01-01T00:00:00Z",
+                "to_date": "2024-01-02T00:00:00Z",
+                "max_active_runs": max_active_runs,
+            },
+        )
+        assert response.status_code == 422
+        assert response.json()["detail"][0]["loc"] == ["body", 
"max_active_runs"]
+
     @pytest.mark.parametrize(
         ("repro_act", "repro_exp", "run_backwards", "status_code"),
         [
diff --git a/airflow-ctl/src/airflowctl/api/datamodels/generated.py 
b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
index 7ed99bea665..a705d2eaf66 100644
--- a/airflow-ctl/src/airflowctl/api/datamodels/generated.py
+++ b/airflow-ctl/src/airflowctl/api/datamodels/generated.py
@@ -1842,7 +1842,7 @@ class BackfillPostBody(BaseModel):
     run_backwards: Annotated[bool | None, Field(title="Run Backwards")] = False
     dag_run_conf: Annotated[dict[str, Any] | None, Field(title="Dag Run 
Conf")] = None
     reprocess_behavior: ReprocessBehavior | None = "none"
-    max_active_runs: Annotated[int | None, Field(title="Max Active Runs")] = 10
+    max_active_runs: Annotated[int | None, Field(ge=1, title="Max Active 
Runs")] = 10
     run_on_latest_version: Annotated[
         bool | None,
         Field(

Reply via email to