mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(interactions): raise on a non-2xx Gemini interaction fetch
AsyncHTTPHandler.get never raises for status and the Gemini GET transform only raised when the body was not JSON, so a 500 or 404 carrying Gemini's JSON error body parsed as an interaction with no status. A delete on a replica other than the creator then claimed the settlement as released and forwarded the delete instead of failing closed, and the bill was lost. The transform now raises GeminiError with the vendor's status, as the delete transform already does; the in-process poll already retries a fetch that raises
This commit is contained in:
parent
6ce60b9492
commit
44c3026aeb
2 changed files with 34 additions and 1 deletions
|
|
@ -313,6 +313,12 @@ class GoogleAIStudioInteractionsConfig(BaseInteractionsAPIConfig):
|
|||
raw_response: httpx.Response,
|
||||
logging_obj: LiteLLMLoggingObj,
|
||||
) -> InteractionsAPIResponse:
|
||||
if not 200 <= raw_response.status_code < 300:
|
||||
raise GeminiError(
|
||||
message=raw_response.text,
|
||||
status_code=raw_response.status_code,
|
||||
headers=dict(raw_response.headers),
|
||||
)
|
||||
try:
|
||||
raw_json: Final = _interaction_body(raw_response)
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@ Covers:
|
|||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
|
||||
from litellm.interactions.litellm_responses_transformation.streaming_iterator import (
|
||||
LiteLLMResponsesInteractionsStreamingIterator,
|
||||
)
|
||||
from litellm.llms.gemini.common_utils import GeminiError
|
||||
from litellm.llms.gemini.interactions.transformation import (
|
||||
GoogleAIStudioInteractionsConfig,
|
||||
)
|
||||
|
|
@ -464,6 +465,32 @@ class TestInteractionOperationUrls:
|
|||
)
|
||||
|
||||
|
||||
class TestGetInteractionResponse:
|
||||
@pytest.mark.parametrize("status_code", [404, 500])
|
||||
def test_non_2xx_raises_even_when_the_error_body_is_json(
|
||||
self, config: GoogleAIStudioInteractionsConfig, status_code: int
|
||||
) -> None:
|
||||
raw_response = httpx.Response(
|
||||
status_code,
|
||||
json={"error": {"code": status_code, "message": "boom", "status": "INTERNAL"}},
|
||||
request=httpx.Request("GET", "https://generativelanguage.googleapis.com/v1beta/interactions/x"),
|
||||
)
|
||||
with pytest.raises(GeminiError) as raised:
|
||||
config.transform_get_interaction_response(raw_response=raw_response, logging_obj=MagicMock())
|
||||
assert raised.value.status_code == status_code
|
||||
assert "boom" in str(raised.value)
|
||||
|
||||
def test_2xx_parses_the_interaction(self, config: GoogleAIStudioInteractionsConfig) -> None:
|
||||
raw_response = httpx.Response(
|
||||
200,
|
||||
json={"id": "interaction-1", "object": "interaction", "status": "completed", "steps": []},
|
||||
request=httpx.Request("GET", "https://generativelanguage.googleapis.com/v1beta/interactions/x"),
|
||||
)
|
||||
response = config.transform_get_interaction_response(raw_response=raw_response, logging_obj=MagicMock())
|
||||
assert response.id == "interaction-1"
|
||||
assert response.status == "completed"
|
||||
|
||||
|
||||
class TestTransformRequestSchemaCoalescing:
|
||||
"""Test new-schema request coalescing (Api-Revision: 2026-05-20)."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue