From ff8491d6104c1819499613e08d7a5357db814f4c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 23:38:12 +0000 Subject: [PATCH] fix(gemini): map any count_tokens translation failure to a 400 error response Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/gemini/count_tokens/transformation.py | 2 +- .../llms/gemini/test_gemini_common_utils.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/litellm/llms/gemini/count_tokens/transformation.py b/litellm/llms/gemini/count_tokens/transformation.py index aac2915cff5..2114c28491a 100644 --- a/litellm/llms/gemini/count_tokens/transformation.py +++ b/litellm/llms/gemini/count_tokens/transformation.py @@ -442,7 +442,7 @@ def build_count_tokens_payload( if _has_anthropic_shape(system=system, tools=tools, messages=messages): return _build_anthropic_payload(model=model, messages=messages, system=system, tools=tools) return _build_openai_payload(model=model, messages=messages, system=system, tools=tools) - except (KeyError, TypeError, ValueError) as e: + except Exception as e: # noqa: BLE001 # translation is pure; any failure is untranslatable input return InvalidCountTokensRequest(message=f"Invalid token count request: {e!r}") diff --git a/tests/test_litellm/llms/gemini/test_gemini_common_utils.py b/tests/test_litellm/llms/gemini/test_gemini_common_utils.py index 0c666fe601f..eabf1e03217 100644 --- a/tests/test_litellm/llms/gemini/test_gemini_common_utils.py +++ b/tests/test_litellm/llms/gemini/test_gemini_common_utils.py @@ -259,14 +259,21 @@ class TestGoogleAIStudioTokenCounter: assert result.error_message is not None @pytest.mark.asyncio - async def test_count_tokens_translation_error_falls_back(self): + @pytest.mark.parametrize( + "bad_messages", + [ + [{"role": "tool", "content": "orphaned result", "tool_call_id": "missing-call"}], + [{"role": "user", "content": [{"type": "text", "text": 123}]}], + ], + ) + async def test_count_tokens_translation_error_falls_back(self, bad_messages): """Malformed message shapes surface as a 400 error TokenCountResponse so the proxy falls back instead of 500ing.""" token_counter = GoogleAIStudioTokenCounter() result = await token_counter.count_tokens( model_to_use="gemini-2.5-flash", - messages=[{"role": "user", "content": [{"type": "text", "text": 123}]}], + messages=bad_messages, contents=None, deployment={"litellm_params": {"api_key": "test-key"}}, request_model="gemini/gemini-2.5-flash",