diff --git a/litellm/llms/xai/oauth.py b/litellm/llms/xai/oauth.py index 2533f7a9aae..a9455a5d07d 100644 --- a/litellm/llms/xai/oauth.py +++ b/litellm/llms/xai/oauth.py @@ -258,7 +258,12 @@ class XAIOAuthAuthenticator: raise XAIOAuthError( f"xAI OAuth discovery request failed: {exc.response.status_code} {exc.response.text}" ) from exc - data = response.json() + try: + data = response.json() + except ValueError as exc: + raise XAIOAuthError( + "xAI OAuth discovery response was not valid JSON" + ) from exc authorization_endpoint = data.get("authorization_endpoint") token_endpoint = data.get("token_endpoint") if not authorization_endpoint or not token_endpoint: @@ -355,7 +360,10 @@ class XAIOAuthAuthenticator: raise XAIOAuthError( f"xAI OAuth token request failed: {exc.response.status_code} {exc.response.text}" ) from exc - body = response.json() + try: + body = response.json() + except ValueError as exc: + raise XAIOAuthError("xAI OAuth token response was not valid JSON") from exc if not isinstance(body, dict): raise XAIOAuthError("xAI OAuth token response was not an object") return body diff --git a/tests/test_litellm/llms/xai/test_xai_oauth.py b/tests/test_litellm/llms/xai/test_xai_oauth.py index c88f8de7525..c410d2ea502 100644 --- a/tests/test_litellm/llms/xai/test_xai_oauth.py +++ b/tests/test_litellm/llms/xai/test_xai_oauth.py @@ -287,6 +287,19 @@ def test_discover_wraps_http_errors(): ) +def test_discover_wraps_invalid_json_response(): + authenticator = XAIOAuthAuthenticator( + http_client=httpx.Client( + transport=httpx.MockTransport( + lambda request: httpx.Response(200, text="not-json") + ) + ) + ) + + with pytest.raises(XAIOAuthError, match="discovery response was not valid JSON"): + authenticator._discover() + + def test_refresh_discovers_token_endpoint_when_auth_file_is_legacy( tmp_path, monkeypatch ): @@ -340,6 +353,19 @@ def test_exchange_token_rejects_non_object_response(): authenticator._exchange_token("https://auth.x.ai/oauth/token", {}) +def test_exchange_token_wraps_invalid_json_response(): + authenticator = XAIOAuthAuthenticator( + http_client=httpx.Client( + transport=httpx.MockTransport( + lambda request: httpx.Response(200, text="not-json") + ) + ) + ) + + with pytest.raises(XAIOAuthError, match="token response was not valid JSON"): + authenticator._exchange_token("https://auth.x.ai/oauth/token", {}) + + def test_start_callback_server_falls_back_to_ephemeral_port(monkeypatch): calls = [] real_server = xai_oauth_module._CallbackServer