From c69b52416caa64503557161cf38061ea20abd750 Mon Sep 17 00:00:00 2001 From: Harsh Kashyap <55448981+Harsh23Kashyap@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:59:57 +0530 Subject: [PATCH] fix: raise JSONError for malformed API error bodies instead of AssertionError handle_error_response validated the error payload with asserts, but the except clause only caught KeyError/TypeError, so any error body that was not {"error": {...}} - a FastAPI-style {"detail": ...} body, a plain string error, or a non-dict JSON body - escaped as a raw AssertionError instead of the intended error.JSONError. Replace the asserts with explicit isinstance checks that raise JSONError. --- src/together/abstract/api_requestor.py | 11 ++---- tests/unit/test_error_response_handling.py | 40 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 tests/unit/test_error_response_handling.py diff --git a/src/together/abstract/api_requestor.py b/src/together/abstract/api_requestor.py index e956bb3a..5360bab3 100644 --- a/src/together/abstract/api_requestor.py +++ b/src/together/abstract/api_requestor.py @@ -335,19 +335,14 @@ def handle_error_response( rcode: int, stream_error: bool = False, ) -> Exception: - try: - assert isinstance(resp.data, dict) - error_resp = resp.data.get("error") - assert isinstance( - error_resp, dict - ), f"Unexpected error response {error_resp}" - error_data = TogetherErrorResponse(**(error_resp)) - except (KeyError, TypeError): + error_resp = resp.data.get("error") if isinstance(resp.data, dict) else None + if not isinstance(error_resp, dict): raise error.JSONError( "Invalid response object from API: %r (HTTP response code " "was %d)" % (resp.data, rcode), http_status=rcode, ) + error_data = TogetherErrorResponse(**error_resp) utils.log_info( "Together API error received", diff --git a/tests/unit/test_error_response_handling.py b/tests/unit/test_error_response_handling.py new file mode 100644 index 00000000..0624f2f4 --- /dev/null +++ b/tests/unit/test_error_response_handling.py @@ -0,0 +1,40 @@ +import pytest + +from together.abstract.api_requestor import APIRequestor +from together.error import InvalidRequestError, JSONError, RateLimitError +from together.together_response import TogetherResponse + + +class TestHandleErrorResponse: + def test_detail_style_body_raises_json_error(self): + """ + FastAPI-style error bodies ({"detail": ...}) have no "error" object. + The SDK must raise JSONError, not a raw AssertionError. + """ + resp = TogetherResponse({"detail": "Not Found"}, {}) + + with pytest.raises(JSONError): + APIRequestor.handle_error_response(resp, 404) + + def test_non_dict_error_field_raises_json_error(self): + resp = TogetherResponse({"error": "bad request"}, {}) + + with pytest.raises(JSONError): + APIRequestor.handle_error_response(resp, 400) + + def test_non_dict_body_raises_json_error(self): + resp = TogetherResponse(["unexpected", "list"], {}) + + with pytest.raises(JSONError): + APIRequestor.handle_error_response(resp, 500) + + def test_valid_error_body_maps_status_codes(self): + body = {"error": {"message": "rate limited", "type": "rate_limit"}} + resp = TogetherResponse(body, {}) + + assert isinstance( + APIRequestor.handle_error_response(resp, 429), RateLimitError + ) + assert isinstance( + APIRequestor.handle_error_response(resp, 400), InvalidRequestError + )