fix(proxy): map audio_speech errors to their status codes instead of a blanket 500

This commit is contained in:
mateo-berri 2026-08-29 21:10:14 -07:00
parent 608603ee63
commit b67b44bdaa
2 changed files with 39 additions and 1 deletions

View file

@ -10996,7 +10996,15 @@ async def audio_speech(
)
verbose_proxy_logger.error("litellm.proxy.proxy_server.audio_speech(): Exception occured - %s", e)
verbose_proxy_logger.debug(traceback.format_exc())
raise e
if isinstance(e, (ProxyException, HTTPException)):
raise e
raise ProxyException(
message=getattr(e, "message", f"{e}"),
type=getattr(e, "type", "None"),
param=getattr(e, "param", "None"),
openai_code=getattr(e, "code", None),
code=getattr(e, "status_code", 500),
)
@router.post(

View file

@ -86,6 +86,24 @@ def patched_speech_error(monkeypatch):
yield
@pytest.fixture
def patched_speech_provider_rejection(monkeypatch, patched_speech_error):
import litellm
async def _raise(*args, **kwargs):
raise litellm.BadRequestError(
message=(
"Gemini TTS only produces raw PCM16 audio, so response_format='mp3' is not supported."
" Supported response formats: pcm, wav."
),
model="gemini-3.1-flash-tts-preview",
llm_provider="gemini",
)
monkeypatch.setattr(proxy_server, "route_request", _raise)
yield
@pytest.fixture
def patched_transcription(monkeypatch):
router = MagicMock()
@ -198,6 +216,18 @@ def test_audio_speech_error(client, auth_as, patched_speech_error, path):
assert len(response.content) > 0
def test_audio_speech_bad_request_maps_to_400(client, auth_as, patched_speech_provider_rejection):
"""Regression for LIT-6501: a BadRequestError from the speech path surfaced as a generic 500."""
payload = {"model": "gemini-tts", "input": "Hi", "voice": "Kore", "response_format": "mp3"}
with auth_as():
response = client.post("/v1/audio/speech", json=payload)
assert response.status_code == 400
error = response.json()["error"]
assert "response_format='mp3'" in error["message"]
assert "pcm" in error["message"]
assert "wav" in error["message"]
@pytest.mark.parametrize("path", ["/v1/audio/transcriptions", "/audio/transcriptions"])
def test_audio_transcription_happy_path(client, auth_as, patched_transcription, path):
"""Pins ``POST /v1/audio/transcriptions`` / ``POST /audio/transcriptions`` (happy)."""