[Bugfix][Frontend] Return 500 for unexpected speech failures (#6487)

Signed-off-by: z2z23n0 <51999056+z2z23n0@users.noreply.github.com>
Co-authored-by: Canlin Guo <canlinguosdu@gmail.com>
This commit is contained in:
z2z23n0andCanlin Guo authored and GitHub committed 2026-09-24 01:38:05 -07:00
1 parent 926ba72793
commit 3b02e5338a
2 files changed
+60 -5

No files matched your search

@@ -12,6 +12,7 @@ import os
import struct
import wave
from dataclasses import FrozenInstanceError, replace
from http import HTTPStatus
from inspect import Signature, signature
from pathlib import Path
from types import SimpleNamespace
@@ -1012,6 +1013,44 @@ class TestTTSMethods:
assert speed == 1.25
resolve_adapter.assert_not_called()
@pytest.mark.asyncio
async def test_create_speech_cuda_oom_returns_internal_server_error(
self,
speech_server,
mocker: MockerFixture,
):
mocker.patch.object(speech_server, "_check_model", new=mocker.AsyncMock(return_value=None))
mocker.patch.object(
speech_server,
"_generate_audio_bytes",
new=mocker.AsyncMock(side_effect=torch.OutOfMemoryError("CUDA out of memory")),
)
response = await speech_server.create_speech(OpenAICreateSpeechRequest(input="Hello"))
assert isinstance(response, ErrorResponse)
assert response.error.code == HTTPStatus.INTERNAL_SERVER_ERROR
assert response.error.type == "InternalServerError"
@pytest.mark.asyncio
async def test_create_speech_unexpected_failure_returns_internal_server_error(
self,
speech_server,
mocker: MockerFixture,
):
mocker.patch.object(speech_server, "_check_model", new=mocker.AsyncMock(return_value=None))
mocker.patch.object(
speech_server,
"_generate_audio_bytes",
new=mocker.AsyncMock(side_effect=RuntimeError("codec failed")),
)
response = await speech_server.create_speech(OpenAICreateSpeechRequest(input="Hello"))
assert isinstance(response, ErrorResponse)
assert response.error.code == HTTPStatus.INTERNAL_SERVER_ERROR
assert response.error.type == "InternalServerError"
def test_is_tts_detection_no_stage(self, speech_server):
"""Test TTS model detection when no TTS stage exists."""
# Fixture creates server with stage_configs = [] -> _is_tts should be False
@@ -3925,11 +3964,19 @@ class TestAsyncOmniSupportedTasks:
assert "generate" in tasks
def test_api_server_create_speech_wraps_error_response_status(mocker: MockerFixture):
@pytest.mark.parametrize(
("status_code", "err_type"),
[(HTTPStatus.BAD_REQUEST, "BadRequestError"), (HTTPStatus.INTERNAL_SERVER_ERROR, "InternalServerError")],
)
def test_api_server_create_speech_wraps_error_response_status(
mocker: MockerFixture,
status_code: HTTPStatus,
err_type: str,
):
handler = mocker.MagicMock()
handler.create_speech = mocker.AsyncMock(
return_value=ErrorResponse(
error=ErrorInfo(message="bad request", type="BadRequestError", param=None, code=400),
error=ErrorInfo(message="speech failed", type=err_type, param=None, code=status_code),
)
)
@@ -3938,7 +3985,12 @@ def test_api_server_create_speech_wraps_error_response_status(mocker: MockerFixt
response = asyncio.run(api_server_module.create_speech(request, raw_request))
_assert_openai_error_response(response, status_code=400, message="bad request")
_assert_openai_error_response(
response,
status_code=status_code,
message="speech failed",
err_type=err_type,
)
def _make_api_server_request(handler, *, method: str = "POST", path: str = "/v1/audio/voices") -> Request:
@@ -2726,8 +2726,11 @@ class OmniOpenAIServingSpeech(OpenAIServing, AudioMixin):
total_ms,
e,
)
logger.exception("Speech generation failed: %s", e)
return self.create_error_response(f"Speech generation failed: {e}")
return self.create_error_response(
f"Speech generation failed: {e}",
err_type="InternalServerError",
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
)
@staticmethod
def _merge_batch_item(