This is an automated email from the ASF dual-hosted git repository. vatsrahul1001 pushed a commit to branch v3-2-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 2de71db94215fbd840d6fb712a9987bcad465e98 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")
