fix(proxy): stamp model on non-streaming RejectedRequestError replays

This commit is contained in:
devin-ai-integration[bot] 2026-08-05 04:09:22 +00:00 committed by GitHub
parent 31a86daa85
commit 7d7ad8519e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 84 additions and 2 deletions

View file

@ -9248,7 +9248,7 @@ async def chat_completion(
original_exception=e,
request_data=_data,
)
_chat_response = litellm.ModelResponse()
_chat_response = litellm.ModelResponse(model=_data.get("model") or e.model or "")
_chat_response.choices[0].message.content = e.message # type: ignore
if data.get("stream", None) is not None and data["stream"] is True:
@ -9432,7 +9432,7 @@ async def completion(
status_code=(e.status_code if hasattr(e, "status_code") else status.HTTP_400_BAD_REQUEST),
)
else:
_response = litellm.TextCompletionResponse()
_response = litellm.TextCompletionResponse(model=_data.get("model") or e.model or "")
_response.choices[0].text = e.message
return _response
except Exception as e:

View file

@ -11018,3 +11018,85 @@ def test_startup_is_silent_when_mock_testing_params_disabled(caplog):
ProxyStartupEvent._warn_if_mock_testing_params_enabled(general_settings={})
assert MOCK_TESTING_CONFIG_KEY not in caplog.text
@pytest.mark.asyncio
async def test_rejected_request_non_streaming_chat_response_carries_model():
"""A pre-call hook that short-circuits with ``RejectedRequestError`` returns a
200 chat completion, so the payload has to satisfy the OpenAI schema: a null
``model`` makes ``ChatCompletion.model_validate`` raise in every strict client."""
from openai.types.chat import ChatCompletion
from fastapi import Request, Response
from litellm.exceptions import RejectedRequestError
from litellm.proxy.proxy_server import chat_completion
request_data = {"model": "my-model", "messages": [{"role": "user", "content": "hello"}]}
exception = RejectedRequestError(
message="cached answer",
model="my-model",
llm_provider="openai",
request_data=request_data,
)
with patch(
"litellm.proxy.proxy_server._read_request_body",
new_callable=AsyncMock,
return_value=dict(request_data),
), patch(
"litellm.proxy.proxy_server.ProxyBaseLLMRequestProcessing.base_process_llm_request",
new_callable=AsyncMock,
side_effect=exception,
), patch(
"litellm.proxy.proxy_server.proxy_logging_obj"
) as mock_proxy_logging:
mock_proxy_logging.post_call_failure_hook = AsyncMock()
response = await chat_completion(
request=MagicMock(spec=Request),
fastapi_response=MagicMock(spec=Response),
user_api_key_dict=UserAPIKeyAuth(),
)
assert response.model == "my-model"
ChatCompletion.model_validate(response.model_dump())
@pytest.mark.asyncio
async def test_rejected_request_non_streaming_text_completion_carries_model():
"""Same contract on /v1/completions: the rejection replay is a 200 the SDK parses
as a ``Completion``, which also requires a string ``model``."""
from fastapi import Request, Response
from litellm.exceptions import RejectedRequestError
from litellm.proxy.proxy_server import completion
request_data = {"model": "my-model", "prompt": "hello"}
exception = RejectedRequestError(
message="cached answer",
model="my-model",
llm_provider="openai",
request_data=request_data,
)
with patch(
"litellm.proxy.proxy_server._read_request_body",
new_callable=AsyncMock,
return_value=dict(request_data),
), patch(
"litellm.proxy.proxy_server.ProxyBaseLLMRequestProcessing.base_process_llm_request",
new_callable=AsyncMock,
side_effect=exception,
), patch(
"litellm.proxy.proxy_server.proxy_logging_obj"
) as mock_proxy_logging:
mock_proxy_logging.post_call_failure_hook = AsyncMock()
response = await completion(
request=MagicMock(spec=Request),
fastapi_response=MagicMock(spec=Response),
user_api_key_dict=UserAPIKeyAuth(),
)
assert response.model == "my-model"