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

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


The following commit(s) were added to refs/heads/v3-2-test by this push:
     new 522e916e14a [v3-2-test] API: Return 400 instead of 500 from 
materialize_asset for invalid validation input (#67445) (#67526)
522e916e14a is described below

commit 522e916e14aca4c70fb7e6776bc55c2b80c38ca4
Author: Jason(Zhe-You) Liu <[email protected]>
AuthorDate: Wed May 27 16:43:08 2026 +0800

    [v3-2-test] API: Return 400 instead of 500 from materialize_asset for 
invalid validation input (#67445) (#67526)
    
    The materialize_asset POST endpoint passed user input (dag_run_id,
    logical_date/data_interval pairing, partition_key) straight through to
    MaterializeAssetBody.validate_context() and dag.create_dagrun(), which raise
    ValueError / ParamValidationError on invalid input (e.g. dag_run_id 
containing
    '..', invalid partition_key type, logical_date/data_interval mismatch). 
Those
    exceptions escaped uncaught and were returned as 500 Internal Server Error,
    even though the route's OpenAPI spec already documents 400 for this case.
    
    Wrap the validate_context / create_dagrun calls in try/except and re-raise 
as
    HTTPException(400) with the validator's message in the detail, matching the
    sibling pattern in dag_run.trigger_dag_run.
    
    Regression test asserts dag_run_id='bad..id' returns 400, not 500.
    (cherry picked from commit 0120ba7fd5be8b6d5e7e4184209fb0479127f2d8)
    
    Co-authored-by: Deepak kumar <[email protected]>
---
 .../api_fastapi/core_api/routes/public/assets.py   | 34 ++++++++++++----------
 .../core_api/routes/public/test_assets.py          | 13 +++++++++
 2 files changed, 32 insertions(+), 15 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/assets.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/assets.py
index e5d9d4bf228..411d94de6cb 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/assets.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/assets.py
@@ -72,6 +72,7 @@ from airflow.api_fastapi.core_api.security import (
 )
 from airflow.api_fastapi.logging.decorators import action_logging
 from airflow.assets.manager import asset_manager
+from airflow.exceptions import ParamValidationError
 from airflow.models.asset import (
     AssetAliasModel,
     AssetDagRunQueue,
@@ -435,21 +436,24 @@ def materialize_asset(
             f"Dag with dag_id: '{dag_id}' does not allow asset materialization 
runs",
         )
 
-    params = (body or MaterializeAssetBody()).validate_context(dag)
-    return dag.create_dagrun(
-        run_id=params["run_id"],
-        logical_date=params["logical_date"],
-        data_interval=params["data_interval"],
-        run_after=params["run_after"],
-        conf=params["conf"],
-        run_type=DagRunType.ASSET_MATERIALIZATION,
-        triggered_by=DagRunTriggeredByType.REST_API,
-        triggering_user_name=user.get_name(),
-        state=DagRunState.QUEUED,
-        partition_key=params["partition_key"],
-        note=params["note"],
-        session=session,
-    )
+    try:
+        params = (body or MaterializeAssetBody()).validate_context(dag)
+        return dag.create_dagrun(
+            run_id=params["run_id"],
+            logical_date=params["logical_date"],
+            data_interval=params["data_interval"],
+            run_after=params["run_after"],
+            conf=params["conf"],
+            run_type=DagRunType.ASSET_MATERIALIZATION,
+            triggered_by=DagRunTriggeredByType.REST_API,
+            triggering_user_name=user.get_name(),
+            state=DagRunState.QUEUED,
+            partition_key=params["partition_key"],
+            note=params["note"],
+            session=session,
+        )
+    except (ParamValidationError, ValueError) as e:
+        raise HTTPException(status.HTTP_400_BAD_REQUEST, str(e)) from e
 
 
 @assets_router.get(
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_assets.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_assets.py
index 26fe24888ac..ba6a4200959 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_assets.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_assets.py
@@ -1551,6 +1551,19 @@ class TestPostAssetMaterialize(TestAssets):
                 user=mock.ANY,
             )
 
+    @pytest.mark.usefixtures("configure_git_connection_for_dag_bundle")
+    def test_should_respond_400_on_invalid_dag_run_id(self, test_client):
+        """A dag_run_id failing DagRun.validate_run_id triggers ValueError.
+
+        It must surface as 400 BAD_REQUEST, not 500 INTERNAL_SERVER_ERROR.
+        """
+        response = test_client.post(
+            "/assets/1/materialize",
+            json={"dag_run_id": "bad id"},
+        )
+        assert response.status_code == 400
+        assert "does not match regex pattern" in response.json()["detail"]
+
 
 class TestGetAssetQueuedEvents(TestQueuedEventEndpoint):
     @pytest.mark.usefixtures("time_freezer")

Reply via email to