diff --git a/plugins/video_gen/xai/__init__.py b/plugins/video_gen/xai/__init__.py index edc981c78ab49..5e59f15d3a61d 100644 --- a/plugins/video_gen/xai/__init__.py +++ b/plugins/video_gen/xai/__init__.py @@ -520,8 +520,8 @@ def _run_xai_video_coroutine( except Exception as exc: logger.warning("xAI video %s unexpected failure: %s", operation_label, exc, exc_info=True) return error_response( - error=f"xAI video {operation_label} failed: {exc}", - error_type="api_error", + error=f"xAI video {operation_label} failed: {type(exc).__name__}: {exc}", + error_type=_xai_video_wrapper_error_type(exc), provider="xai", model=model or DEFAULT_MODEL, prompt=prompt, @@ -529,6 +529,14 @@ def _run_xai_video_coroutine( ) +def _xai_video_wrapper_error_type(exc: Exception) -> str: + if isinstance(exc, (TimeoutError, httpx.TimeoutException)): + return "timeout" + if isinstance(exc, httpx.TransportError): + return "connection_error" + return "api_error" + + async def _generate_xai_video_async( *, prompt: str, diff --git a/tests/plugins/video_gen/test_xai_plugin.py b/tests/plugins/video_gen/test_xai_plugin.py index eb495b96951e5..5b8cba49b72fb 100644 --- a/tests/plugins/video_gen/test_xai_plugin.py +++ b/tests/plugins/video_gen/test_xai_plugin.py @@ -146,6 +146,46 @@ def test_xai_no_operation_kwarg(): assert result["error_type"] in {"auth_required", "api_error"} +def test_xai_video_wrapper_preserves_read_timeout_error_type(): + import httpx + from plugins.video_gen.xai import _run_xai_video_coroutine + + async def fail_with_timeout(): + raise httpx.ReadTimeout("") + + result = _run_xai_video_coroutine( + fail_with_timeout(), + operation_label="generation", + model="grok-imagine-video", + prompt="animate the selected image", + aspect_ratio="16:9", + ) + + assert result["success"] is False + assert result["error_type"] == "timeout" + assert "ReadTimeout" in result["error"] + + +def test_xai_video_wrapper_preserves_transport_error_type(): + import httpx + from plugins.video_gen.xai import _run_xai_video_coroutine + + async def fail_with_transport_error(): + raise httpx.ConnectError("network unavailable") + + result = _run_xai_video_coroutine( + fail_with_transport_error(), + operation_label="generation", + model="grok-imagine-video", + prompt="animate the selected image", + aspect_ratio="16:9", + ) + + assert result["success"] is False + assert result["error_type"] == "connection_error" + assert "ConnectError" in result["error"] + + def test_xai_video_output_urls_prefers_stored_public_url(): from plugins.video_gen.xai import _xai_video_output_urls