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

vincbeck 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 9c4ebf337fc Use `HTTP_422_UNPROCESSABLE_CONTENT` instead of 
`HTTP_422_UNPROCESSABLE_ENTITY` (#58828)
9c4ebf337fc is described below

commit 9c4ebf337fc0add2cdb40468063f1739a759d02a
Author: Vincent <[email protected]>
AuthorDate: Mon Dec 1 10:53:19 2025 -0500

    Use `HTTP_422_UNPROCESSABLE_CONTENT` instead of 
`HTTP_422_UNPROCESSABLE_ENTITY` (#58828)
---
 .../src/airflow/api_fastapi/common/parameters.py   |  9 ++++----
 airflow-core/src/airflow/api_fastapi/compat.py     | 26 ++++++++++++++++++++++
 .../api_fastapi/core_api/routes/public/dags.py     |  5 +++--
 .../api_fastapi/execution_api/routes/dag_runs.py   |  5 +++--
 .../execution_api/routes/task_instances.py         | 15 +++++++------
 .../providers/fab/auth_manager/fab_auth_manager.py |  2 +-
 6 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/common/parameters.py 
b/airflow-core/src/airflow/api_fastapi/common/parameters.py
index 2f60b13b27e..914d6284fc5 100644
--- a/airflow-core/src/airflow/api_fastapi/common/parameters.py
+++ b/airflow-core/src/airflow/api_fastapi/common/parameters.py
@@ -32,13 +32,14 @@ from typing import (
     overload,
 )
 
-from fastapi import Depends, HTTPException, Query, status
+from fastapi import Depends, HTTPException, Query
 from pendulum.parsing.exceptions import ParserError
 from pydantic import AfterValidator, BaseModel, NonNegativeInt
 from sqlalchemy import Column, and_, case, func, not_, or_, select as 
sql_select
 from sqlalchemy.inspection import inspect
 
 from airflow._shared.timezones import timezone
+from airflow.api_fastapi.compat import HTTP_422_UNPROCESSABLE_CONTENT
 from airflow.api_fastapi.core_api.base import OrmClause
 from airflow.api_fastapi.core_api.security import GetUserDep
 from airflow.models import Base
@@ -779,7 +780,7 @@ def _transform_dag_run_states(states: Iterable[str] | None) 
-> list[DagRunState
         return [None if s in ("none", None) else DagRunState(s) for s in 
states]
     except ValueError:
         raise HTTPException(
-            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+            status_code=HTTP_422_UNPROCESSABLE_CONTENT,
             detail=f"Invalid value for state. Valid values are {', 
'.join(DagRunState)}",
         )
 
@@ -805,7 +806,7 @@ def _transform_dag_run_types(types: list[str] | None) -> 
list[DagRunType | None]
         return [None if run_type in ("none", None) else DagRunType(run_type) 
for run_type in types]
     except ValueError:
         raise HTTPException(
-            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+            status_code=HTTP_422_UNPROCESSABLE_CONTENT,
             detail=f"Invalid value for run type. Valid values are {', 
'.join(DagRunType)}",
         )
 
@@ -843,7 +844,7 @@ def _transform_ti_states(states: list[str] | None) -> 
list[TaskInstanceState | N
         return [None if s in ("no_status", "none", None) else 
TaskInstanceState(s) for s in states]
     except ValueError:
         raise HTTPException(
-            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+            status_code=HTTP_422_UNPROCESSABLE_CONTENT,
             detail=f"Invalid value for state. Valid values are {', 
'.join(TaskInstanceState)}",
         )
 
diff --git a/airflow-core/src/airflow/api_fastapi/compat.py 
b/airflow-core/src/airflow/api_fastapi/compat.py
new file mode 100644
index 00000000000..06d8822bf95
--- /dev/null
+++ b/airflow-core/src/airflow/api_fastapi/compat.py
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+try:
+    from starlette.status import HTTP_422_UNPROCESSABLE_CONTENT
+except ImportError:
+    from starlette.status import (  # type: ignore[no-redef]
+        HTTP_422_UNPROCESSABLE_ENTITY as HTTP_422_UNPROCESSABLE_CONTENT,
+    )
+
+__all__ = ["HTTP_422_UNPROCESSABLE_CONTENT"]
diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
index 22d6e48d894..da2407e3612 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/dags.py
@@ -57,6 +57,7 @@ from airflow.api_fastapi.common.parameters import (
     filter_param_factory,
 )
 from airflow.api_fastapi.common.router import AirflowRouter
+from airflow.api_fastapi.compat import HTTP_422_UNPROCESSABLE_CONTENT
 from airflow.api_fastapi.core_api.datamodels.dags import (
     DAGCollectionResponse,
     DAGDetailsResponse,
@@ -178,7 +179,7 @@ def get_dags(
         [
             status.HTTP_400_BAD_REQUEST,
             status.HTTP_404_NOT_FOUND,
-            status.HTTP_422_UNPROCESSABLE_ENTITY,
+            HTTP_422_UNPROCESSABLE_CONTENT,
         ]
     ),
     dependencies=[Depends(requires_access_dag(method="GET"))],
@@ -413,7 +414,7 @@ def unfavorite_dag(dag_id: str, session: SessionDep, user: 
GetUserDep):
         [
             status.HTTP_400_BAD_REQUEST,
             status.HTTP_404_NOT_FOUND,
-            status.HTTP_422_UNPROCESSABLE_ENTITY,
+            HTTP_422_UNPROCESSABLE_CONTENT,
         ]
     ),
     dependencies=[Depends(requires_access_dag(method="DELETE")), 
Depends(action_logging())],
diff --git 
a/airflow-core/src/airflow/api_fastapi/execution_api/routes/dag_runs.py 
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/dag_runs.py
index b3a99bf21a3..5eae430a434 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/routes/dag_runs.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/routes/dag_runs.py
@@ -27,6 +27,7 @@ from airflow.api.common.trigger_dag import trigger_dag
 from airflow.api_fastapi.common.dagbag import DagBagDep, get_dag_for_run
 from airflow.api_fastapi.common.db.common import SessionDep
 from airflow.api_fastapi.common.types import UtcDateTime
+from airflow.api_fastapi.compat import HTTP_422_UNPROCESSABLE_CONTENT
 from airflow.api_fastapi.execution_api.datamodels.dagrun import 
DagRunStateResponse, TriggerDAGRunPayload
 from airflow.api_fastapi.execution_api.datamodels.taskinstance import DagRun
 from airflow.exceptions import DagRunAlreadyExists
@@ -48,7 +49,7 @@ log = logging.getLogger(__name__)
         status.HTTP_400_BAD_REQUEST: {"description": "DAG has import errors 
and cannot be triggered"},
         status.HTTP_404_NOT_FOUND: {"description": "DAG not found for the 
given dag_id"},
         status.HTTP_409_CONFLICT: {"description": "DAG Run already exists for 
the given dag_id"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid 
payload"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid payload"},
     },
 )
 def trigger_dag_run(
@@ -100,7 +101,7 @@ def trigger_dag_run(
     responses={
         status.HTTP_400_BAD_REQUEST: {"description": "DAG has import errors 
and cannot be triggered"},
         status.HTTP_404_NOT_FOUND: {"description": "DAG not found for the 
given dag_id"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid 
payload"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid payload"},
     },
 )
 def clear_dag_run(
diff --git 
a/airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py 
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py
index 43561cbf1d0..56111db979c 100644
--- 
a/airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py
+++ 
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py
@@ -41,6 +41,7 @@ from airflow._shared.timezones import timezone
 from airflow.api_fastapi.common.dagbag import DagBagDep, 
get_latest_version_of_dag
 from airflow.api_fastapi.common.db.common import SessionDep
 from airflow.api_fastapi.common.types import UtcDateTime
+from airflow.api_fastapi.compat import HTTP_422_UNPROCESSABLE_CONTENT
 from airflow.api_fastapi.execution_api.datamodels.taskinstance import (
     InactiveAssetsResponse,
     PrevSuccessfulDagRunResponse,
@@ -96,7 +97,7 @@ log = structlog.get_logger(__name__)
     responses={
         status.HTTP_404_NOT_FOUND: {"description": "Task Instance not found"},
         status.HTTP_409_CONFLICT: {"description": "The TI is already in the 
requested state"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid payload 
for the state transition"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid payload for 
the state transition"},
     },
     response_model_exclude_unset=True,
 )
@@ -337,7 +338,7 @@ def _get_upstream_map_indexes(
     responses={
         status.HTTP_404_NOT_FOUND: {"description": "Task Instance not found"},
         status.HTTP_409_CONFLICT: {"description": "The TI is already in the 
requested state"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid payload 
for the state transition"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid payload for 
the state transition"},
     },
 )
 def ti_update_state(
@@ -581,7 +582,7 @@ def _create_ti_state_update_query_and_update_state(
     status_code=status.HTTP_204_NO_CONTENT,
     responses={
         status.HTTP_404_NOT_FOUND: {"description": "Task Instance not found"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid payload 
for the state transition"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid payload for 
the state transition"},
     },
 )
 def ti_skip_downstream(
@@ -628,7 +629,7 @@ def ti_skip_downstream(
         status.HTTP_409_CONFLICT: {
             "description": "The TI attempting to heartbeat should be 
terminated for the given reason"
         },
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid payload 
for the state transition"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid payload for 
the state transition"},
     },
 )
 def ti_heartbeat(
@@ -703,7 +704,7 @@ def ti_heartbeat(
     # TODO: Do we need to use create_openapi_http_exception_doc here?
     responses={
         status.HTTP_404_NOT_FOUND: {"description": "Task Instance not found"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {
+        HTTP_422_UNPROCESSABLE_CONTENT: {
             "description": "Invalid payload for the setting rendered task 
instance fields"
         },
     },
@@ -735,7 +736,7 @@ def ti_put_rtif(
     status_code=status.HTTP_204_NO_CONTENT,
     responses={
         status.HTTP_404_NOT_FOUND: {"description": "Task Instance not found"},
-        status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid 
rendered_map_index value"},
+        HTTP_422_UNPROCESSABLE_CONTENT: {"description": "Invalid 
rendered_map_index value"},
     },
 )
 def ti_patch_rendered_map_index(
@@ -750,7 +751,7 @@ def ti_patch_rendered_map_index(
     if not rendered_map_index:
         log.error("rendered_map_index cannot be empty")
         raise HTTPException(
-            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+            status_code=HTTP_422_UNPROCESSABLE_CONTENT,
             detail="rendered_map_index cannot be empty",
         )
 
diff --git 
a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py 
b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
index eaf98737394..5c4a9e98d55 100644
--- a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -78,6 +78,7 @@ from airflow.providers.fab.www.security import permissions
 from airflow.providers.fab.www.security.permissions import (
     ACTION_CAN_READ,
     RESOURCE_AUDIT_LOG,
+    RESOURCE_BACKFILL,
     RESOURCE_CLUSTER_ACTIVITY,
     RESOURCE_CONFIG,
     RESOURCE_CONNECTION,
@@ -105,7 +106,6 @@ from airflow.providers.fab.www.utils import (
     get_fab_action_from_method_map,
     get_method_from_fab_action_map,
 )
-from airflow.security.permissions import RESOURCE_BACKFILL
 from airflow.utils.session import NEW_SESSION, create_session, provide_session
 from airflow.utils.yaml import safe_load
 

Reply via email to