fix(exception_mapping): handle exceptions without response parameter (#18919)

When extract_and_raise_litellm_exception tries to raise a LiteLLM exception
from an error string, it was always passing the response parameter. However,
some exceptions like APIConnectionError don't accept this parameter, causing
a TypeError.

This fix tries to raise the exception with the response parameter first,
and falls back to raising without it if a TypeError occurs.

This fixes the error:
TypeError: APIConnectionError.__init__() got an unexpected keyword argument 'response'

Which was occurring when Gemini returned UNEXPECTED_TOOL_CALL finish reason
and LiteLLM tried to convert the error to an APIConnectionError.

Fixes: cascading error when Gemini uses thinking feature (__thought__ tool calls)
This commit is contained in:
Debnil Sur 2026-01-13 14:33:05 -08:00 • committed by GitHub
parent f76938af5e
commit d94af171db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 93 additions and 6 deletions

View file

@ -197,12 +197,22 @@ def extract_and_raise_litellm_exception(
exception_name = exception_name.strip().replace("litellm.", "")
raised_exception_obj = getattr(litellm, exception_name, None)
if raised_exception_obj:
raise raised_exception_obj(
message=error_str,
llm_provider=custom_llm_provider,
model=model,
response=response,
)
# Try with response parameter first, fall back to without it
# Some exceptions (e.g., APIConnectionError) don't accept response param
try:
raise raised_exception_obj(
message=error_str,
llm_provider=custom_llm_provider,
model=model,
response=response,
)
except TypeError:
# Exception doesn't accept response parameter
raise raised_exception_obj(
message=error_str,
llm_provider=custom_llm_provider,
model=model,
)
def exception_type( # type: ignore # noqa: PLR0915

View file

@ -12,6 +12,7 @@ sys.path.insert(
from litellm.litellm_core_utils.exception_mapping_utils import (
ExceptionCheckers,
exception_type,
extract_and_raise_litellm_exception,
)
# Test cases for is_error_str_context_window_exceeded
@ -269,3 +270,79 @@ def test_vertex_ai_rate_limit_error_mapping(error_message, should_raise_rate_lim
original_exception=original_exception,
custom_llm_provider=custom_llm_provider,
)
class TestExtractAndRaiseLitellmException:
"""Tests for extract_and_raise_litellm_exception function"""
def test_extract_and_raise_api_connection_error_without_response(self):
"""
Test that APIConnectionError can be raised without response parameter.
This is a regression test for the bug where extract_and_raise_litellm_exception
would fail with TypeError when trying to raise APIConnectionError with a
response parameter, since APIConnectionError doesn't accept that parameter.
Relevant Issue: https://github.com/BerriAI/litellm/issues/XXXXX
"""
error_str = "litellm.APIConnectionError: GeminiException - some error message"
with pytest.raises(litellm.APIConnectionError) as excinfo:
extract_and_raise_litellm_exception(
response=None,
error_str=error_str,
model="gemini/gemini-3-pro-preview",
custom_llm_provider="gemini",
)
assert "APIConnectionError" in str(excinfo.value)
def test_extract_and_raise_bad_request_error_with_response(self):
"""
Test that BadRequestError can be raised with response parameter.
BadRequestError does accept the response parameter, so this should work.
"""
error_str = "litellm.BadRequestError: Invalid request format"
with pytest.raises(litellm.BadRequestError) as excinfo:
extract_and_raise_litellm_exception(
response=None,
error_str=error_str,
model="gpt-4",
custom_llm_provider="openai",
)
assert "BadRequestError" in str(excinfo.value)
def test_extract_and_raise_context_window_exceeded_error(self):
"""
Test that ContextWindowExceededError can be raised.
"""
error_str = "litellm.ContextWindowExceededError: Token limit exceeded"
with pytest.raises(litellm.ContextWindowExceededError) as excinfo:
extract_and_raise_litellm_exception(
response=None,
error_str=error_str,
model="gpt-4",
custom_llm_provider="openai",
)
assert "ContextWindowExceededError" in str(excinfo.value)
def test_no_exception_raised_for_non_litellm_error(self):
"""
Test that no exception is raised for non-litellm error strings.
"""
error_str = "Some generic error that is not a litellm exception"
# Should not raise any exception
result = extract_and_raise_litellm_exception(
response=None,
error_str=error_str,
model="gpt-4",
custom_llm_provider="openai",
)
assert result is None