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)
