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

ephraimbuddy pushed a commit to branch dag-processor-http-manager
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 37678c8652b1288603cadf3eed8dd61a38227dd2
Author: Ephraim Anierobi <[email protected]>
AuthorDate: Wed Oct 14 13:29:52 2026 +0100

    Parse Execution API JSON errors that carry media type parameters
    
    ServerResponseError.from_response compared the Content-Type header for exact
    equality with application/json, so a JSON error sent as
    "application/json; charset=utf-8", or in different letter case, was raised 
as a
    bare HTTPStatusError with its body unread. Callers that inspect the error
    detail, such as the Dag processor client deciding whether its registration 
was
    retired or its Job closed, then found no reason and treated the response as 
an
    unexplained failure.
---
 task-sdk/src/airflow/sdk/api/client.py     |  3 ++-
 task-sdk/tests/task_sdk/api/test_client.py | 13 +++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/task-sdk/src/airflow/sdk/api/client.py 
b/task-sdk/src/airflow/sdk/api/client.py
index 42afaace779..a29617c82e5 100644
--- a/task-sdk/src/airflow/sdk/api/client.py
+++ b/task-sdk/src/airflow/sdk/api/client.py
@@ -1432,7 +1432,8 @@ class ServerResponseError(httpx2.HTTPStatusError):
         if not (400 <= response.status_code < 600):
             return None
 
-        if response.headers.get("content-type") != "application/json":
+        media_type = response.headers.get("content-type", 
"").partition(";")[0].strip().lower()
+        if media_type != "application/json":
             return None
 
         detail: list[RemoteValidationError] | dict[str, Any] | None = None
diff --git a/task-sdk/tests/task_sdk/api/test_client.py 
b/task-sdk/tests/task_sdk/api/test_client.py
index 62fde3373e0..9425c81e8b6 100644
--- a/task-sdk/tests/task_sdk/api/test_client.py
+++ b/task-sdk/tests/task_sdk/api/test_client.py
@@ -199,6 +199,19 @@ class TestClient:
         assert err.value.args == ("Not found",)
         assert err.value.detail is None
 
+    @pytest.mark.parametrize("content_type", ["application/json; 
charset=utf-8", "Application/JSON"])
+    def test_error_parsing_json_media_type_variants(self, content_type):
+        responses = [
+            httpx2.Response(
+                409, content=b'{"detail": {"reason": "job_running"}}', 
headers={"content-type": content_type}
+            )
+        ]
+        client = make_client_w_responses(responses)
+
+        with pytest.raises(ServerResponseError) as err:
+            client.get("http://error";)
+        assert err.value.detail == {"reason": "job_running"}
+
     def test_server_response_error_pickling(self):
         responses = [httpx2.Response(404, json={"detail": {"message": "Invalid 
input"}})]
         client = make_client_w_responses(responses)

Reply via email to