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 b13414865e1 Fix 500 for non-dict JSON bodies on variable/connection 
endpoints (#72683)
b13414865e1 is described below

commit b13414865e100cb181634505f8330d9b5f3baeb2
Author: PoAn Yang <[email protected]>
AuthorDate: Thu Sep 10 19:27:53 2026 +0900

    Fix 500 for non-dict JSON bodies on variable/connection endpoints (#72683)
    
    * Fix 500 for non-dict JSON bodies on variable/connection endpoints
    
    Signed-off-by: PoAn Yang <[email protected]>
    
    * Simplify the comment
    
    Signed-off-by: PoAn Yang <[email protected]>
    
    ---------
    
    Signed-off-by: PoAn Yang <[email protected]>
---
 .../src/airflow/api_fastapi/logging/decorators.py  |  6 ++++--
 .../core_api/routes/public/test_connections.py     | 22 ++++++++++++++++++++++
 .../core_api/routes/public/test_variables.py       | 18 ++++++++++++++++++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/logging/decorators.py 
b/airflow-core/src/airflow/api_fastapi/logging/decorators.py
index 3ed9dd86c79..b459d784b13 100644
--- a/airflow-core/src/airflow/api_fastapi/logging/decorators.py
+++ b/airflow-core/src/airflow/api_fastapi/logging/decorators.py
@@ -203,8 +203,10 @@ def action_logging(event: str | None = None):
         masked_body_json = {}
 
         if has_json_body:
-            request_body = await request.json()
-            if isinstance(request_body, dict):
+            # Non-dict bodies fall through to the endpoint's own 422.
+            parsed_body = await request.json()
+            if isinstance(parsed_body, dict):
+                request_body = parsed_body
                 masked_body_json = {k: secrets_masker.redact(v, k) for k, v in 
request_body.items()}
 
                 if event_name in skip_dry_run_events and 
request_body.get("dry_run", True):
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_connections.py
 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_connections.py
index a9822e5afaf..84563368126 100644
--- 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_connections.py
+++ 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_connections.py
@@ -368,6 +368,28 @@ class TestPostConnection(TestConnectionEndpoint):
             ]
         }
 
+    @pytest.mark.parametrize(
+        "body",
+        [
+            [{"connection_id": TEST_CONN_ID, "conn_type": TEST_CONN_TYPE}],
+            '{"connection_id": "a"}',
+            42,
+        ],
+        ids=["list", "string", "number"],
+    )
+    def test_post_should_respond_422_for_non_dict_json_body(self, test_client, 
session, body):
+        """The audit-log dependency reads the body before validation, so a 
non-object body still gets a 422."""
+        response = test_client.post("/connections", json=body)
+        assert response.status_code == 422
+        assert response.json()["detail"][0]["loc"] == ["body"]
+        _check_last_log(
+            session,
+            dag_id=None,
+            event="post_connection",
+            logical_date=None,
+            expected_extra={"method": "POST"},
+        )
+
     @conf_vars({("core", "multi_team"): "False"})
     def test_post_rejects_team_name_when_multi_team_disabled(self, 
test_client):
         response = test_client.post(
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_variables.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_variables.py
index ec5f915dc43..9a61130e3c1 100644
--- 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_variables.py
+++ 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_variables.py
@@ -805,6 +805,24 @@ class TestPostVariable(TestVariableEndpoint):
             ]
         }
 
+    @pytest.mark.parametrize(
+        "body",
+        [[{"key": "new variable key", "value": "new variable value"}], 
'{"key": "a"}', 42],
+        ids=["list", "string", "number"],
+    )
+    def test_post_should_respond_422_for_non_dict_json_body(self, test_client, 
session, body):
+        """The audit-log dependency reads the body before validation, so a 
non-object body still gets a 422."""
+        response = test_client.post("/variables", json=body)
+        assert response.status_code == 422
+        assert response.json()["detail"][0]["loc"] == ["body"]
+        check_last_log(
+            session,
+            dag_id=None,
+            event="post_variable",
+            logical_date=None,
+            expected_extra={"method": "POST"},
+        )
+
     @conf_vars({("core", "multi_team"): "False"})
     def test_post_rejects_team_name_when_multi_team_disabled(self, 
test_client):
         body = {

Reply via email to