diff --git a/litellm/llms/vertex_ai/vector_stores/search_api/transformation.py b/litellm/llms/vertex_ai/vector_stores/search_api/transformation.py index 2e55aed3c0b..46dedb3d0a4 100644 --- a/litellm/llms/vertex_ai/vector_stores/search_api/transformation.py +++ b/litellm/llms/vertex_ai/vector_stores/search_api/transformation.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union import httpx from litellm import get_model_info +from litellm.exceptions import BadRequestError from litellm.litellm_core_utils.url_utils import encode_url_path_segment from litellm.llms.base_llm.vector_store.transformation import BaseVectorStoreConfig from litellm.llms.vertex_ai.vertex_llm_base import VertexBase @@ -85,11 +86,12 @@ class VertexSearchAPIVectorStoreConfig(BaseVectorStoreConfig, VertexBase): Validate ``extra_body`` against the supported-field allowlist for the active serving config (engine/app vs data store). - Raises ``ValueError`` if the caller includes a target-selecting field - (e.g. ``servingConfig``) or any field not supported for the active mode, - so the request fails loudly instead of silently searching the wrong - target. Engine-only fields (``dataStoreSpecs``, ``numResultsPerDataStore``) - are rejected in data-store mode where they are meaningless. + Raises ``BadRequestError`` (HTTP 400) if the caller includes a + target-selecting field (e.g. ``servingConfig``) or any field not + supported for the active mode, so the request fails loudly instead of + silently searching the wrong target. Engine-only fields + (``dataStoreSpecs``, ``numResultsPerDataStore``) are rejected in + data-store mode where they are meaningless. """ supported = cls.get_supported_extra_body_fields(is_engine=is_engine) filtered = { @@ -98,18 +100,26 @@ class VertexSearchAPIVectorStoreConfig(BaseVectorStoreConfig, VertexBase): target_selecting = set(filtered) & VERTEX_SEARCH_TARGET_SELECTING_FIELDS if target_selecting: - raise ValueError( - "Vertex AI Search extra_body may not set target-selecting fields " - f"{sorted(target_selecting)}: the data store is scoped by " - "vector_store_id / vertex_engine_id and cannot be overridden per request." + raise BadRequestError( + message=( + "Vertex AI Search extra_body may not set target-selecting fields " + f"{sorted(target_selecting)}: the data store is scoped by " + "vector_store_id / vertex_engine_id and cannot be overridden per request." + ), + model="vertex_ai/search_api", + llm_provider="vertex_ai", ) unsupported = set(filtered) - supported if unsupported: mode = "engine/app" if is_engine else "data store" - raise ValueError( - f"Unsupported Vertex AI Search extra_body fields {sorted(unsupported)} " - f"for {mode} mode. Supported fields: {sorted(supported)}." + raise BadRequestError( + message=( + f"Unsupported Vertex AI Search extra_body fields {sorted(unsupported)} " + f"for {mode} mode. Supported fields: {sorted(supported)}." + ), + model="vertex_ai/search_api", + llm_provider="vertex_ai", ) return filtered diff --git a/tests/test_litellm/llms/vertex_ai/test_vertex_ai_search_vector_store_transformation.py b/tests/test_litellm/llms/vertex_ai/test_vertex_ai_search_vector_store_transformation.py index 8a83ae3a894..034f85f5a0b 100644 --- a/tests/test_litellm/llms/vertex_ai/test_vertex_ai_search_vector_store_transformation.py +++ b/tests/test_litellm/llms/vertex_ai/test_vertex_ai_search_vector_store_transformation.py @@ -2,6 +2,7 @@ from types import SimpleNamespace import pytest +from litellm.exceptions import BadRequestError from litellm.llms.vertex_ai.vector_stores.search_api.transformation import ( VertexSearchAPIVectorStoreConfig, ) @@ -209,32 +210,39 @@ def test_engine_search_request_forwards_num_results_per_data_store(): def test_datastore_search_request_rejects_datastorespecs(): specs = [{"dataStore": "projects/p/.../dataStores/ds-beta"}] - with pytest.raises(ValueError, match="data store mode"): + with pytest.raises(BadRequestError, match="data store mode"): _datastore_search_request(extra_body={"dataStoreSpecs": specs}) def test_datastore_search_request_rejects_num_results_per_data_store(): - with pytest.raises(ValueError, match="data store mode"): + with pytest.raises(BadRequestError, match="data store mode"): _datastore_search_request(extra_body={"numResultsPerDataStore": 3}) @pytest.mark.parametrize("field", ["branch", "servingConfig", "entity"]) def test_search_request_rejects_target_selecting_fields(field): - with pytest.raises(ValueError, match="target-selecting"): + with pytest.raises(BadRequestError, match="target-selecting"): _search_request(extra_body={field: "x"}) @pytest.mark.parametrize("field", ["branch", "servingConfig", "entity"]) def test_datastore_search_request_rejects_target_selecting_fields(field): - with pytest.raises(ValueError, match="target-selecting"): + with pytest.raises(BadRequestError, match="target-selecting"): _datastore_search_request(extra_body={field: "x"}) def test_search_request_rejects_unsupported_extra_body_field(): - with pytest.raises(ValueError, match="Unsupported Vertex AI Search extra_body"): + with pytest.raises(BadRequestError, match="Unsupported Vertex AI Search extra_body"): _search_request(extra_body={"notARealField": True}) +def test_rejected_extra_body_raises_http_400(): + with pytest.raises(BadRequestError) as exc_info: + _search_request(extra_body={"notARealField": True}) + + assert exc_info.value.status_code == 400 + + def test_search_request_forwards_supported_extra_body_fields(): _, body = _search_request( extra_body={