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

pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new efec6ba3529 Fix `clearTaskInstances` returning 500 instead of 422 on 
invalid body (#70237)
efec6ba3529 is described below

commit efec6ba3529aad93115276c18eee59eb08da3877
Author: SreeramaYeshwanthGowd <[email protected]>
AuthorDate: Thu Aug 13 21:59:18 2026 +0530

    Fix `clearTaskInstances` returning 500 instead of 422 on invalid body 
(#70237)
    
    The ClearTaskInstancesBody validator raised pydantic.ValidationError with a
    string argument for its invalid-input branches. In Pydantic v2 that 
constructor
    call raises TypeError, which the core API has no handler for, so an invalid
    request body surfaced as 500 Internal Server Error instead of a 422. Raising
    ValueError lets Pydantic report the problem as a normal 422, matching the
    sibling PatchTaskInstanceBody validator in the same file.
---
 .../core_api/datamodels/task_instances.py          | 13 ++++-----
 .../core_api/routes/public/test_task_instances.py  | 34 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 7 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/task_instances.py 
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/task_instances.py
index 7166835ce61..cd83cd192aa 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/task_instances.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/task_instances.py
@@ -30,7 +30,6 @@ from pydantic import (
     NonNegativeInt,
     StringConstraints,
     Tag,
-    ValidationError,
     field_validator,
     model_validator,
 )
@@ -239,18 +238,18 @@ class ClearTaskInstancesBody(StrictBaseModel):
     def validate_model(cls, data: Any) -> Any:
         """Validate clear task instance form."""
         if data.get("only_failed") and data.get("only_running"):
-            raise ValidationError("only_failed and only_running both are set 
to True")
+            raise ValueError("only_failed and only_running both are set to 
True")
         if data.get("start_date") and data.get("end_date"):
             if data.get("start_date") > data.get("end_date"):
-                raise ValidationError("end_date is sooner than start_date")
+                raise ValueError("end_date is sooner than start_date")
         if data.get("start_date") and data.get("end_date") and 
data.get("dag_run_id"):
-            raise ValidationError("Exactly one of dag_run_id or (start_date 
and end_date) must be provided")
+            raise ValueError("Exactly one of dag_run_id or (start_date and 
end_date) must be provided")
         if data.get("start_date") and data.get("dag_run_id"):
-            raise ValidationError("Exactly one of dag_run_id or start_date 
must be provided")
+            raise ValueError("Exactly one of dag_run_id or start_date must be 
provided")
         if data.get("end_date") and data.get("dag_run_id"):
-            raise ValidationError("Exactly one of dag_run_id or end_date must 
be provided")
+            raise ValueError("Exactly one of dag_run_id or end_date must be 
provided")
         if isinstance(data.get("task_ids"), list) and 
len(data.get("task_ids")) < 1:
-            raise ValidationError("task_ids list should have at least 1 
element.")
+            raise ValueError("task_ids list should have at least 1 element.")
         return data
 
 
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
index 0efc3e003e0..7c945edf954 100644
--- 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
+++ 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_task_instances.py
@@ -3694,6 +3694,40 @@ class 
TestPostClearTaskInstances(TestTaskInstanceEndpoint):
         )
         assert response.status_code == 403
 
+    @pytest.mark.parametrize(
+        "payload",
+        [
+            pytest.param(
+                {"only_failed": True, "only_running": True},
+                id="only_failed_and_only_running",
+            ),
+            pytest.param(
+                {"start_date": "2024-01-02T00:00:00Z", "end_date": 
"2024-01-01T00:00:00Z"},
+                id="start_date_after_end_date",
+            ),
+            pytest.param(
+                {
+                    "start_date": "2024-01-01T00:00:00Z",
+                    "end_date": "2024-01-02T00:00:00Z",
+                    "dag_run_id": "run_1",
+                },
+                id="dag_run_id_with_start_and_end_date",
+            ),
+            pytest.param(
+                {"start_date": "2024-01-01T00:00:00Z", "dag_run_id": "run_1"},
+                id="dag_run_id_with_start_date",
+            ),
+            pytest.param(
+                {"end_date": "2024-01-01T00:00:00Z", "dag_run_id": "run_1"},
+                id="dag_run_id_with_end_date",
+            ),
+            pytest.param({"task_ids": []}, id="empty_task_ids"),
+        ],
+    )
+    def test_should_respond_422_on_invalid_body(self, test_client, payload):
+        response = 
test_client.post("/dags/example_python_operator/clearTaskInstances", 
json=payload)
+        assert response.status_code == 422
+
     @pytest.mark.parametrize(
         ("main_dag", "task_instances", "request_dag", "payload", 
"expected_ti"),
         [

Reply via email to