fix(vector-stores): reject searches without a query

This commit is contained in:
Yujong Lee 2026-09-05 08:28:02 -07:00
parent 685a24b444
commit 2079b2e29c
3 changed files with 28 additions and 17 deletions

View file

@ -159,6 +159,8 @@ async def vector_store_search(
)
data = await _read_request_body(request=request)
if "query" not in data:
raise HTTPException(status_code=400, detail={"error": "query is required"})
reject_caller_embedding_selection_params(payload=data, source="the search request body")
data["vector_store_id"] = vector_store_id

View file

@ -200,27 +200,16 @@ class TestVectorStores:
assert deleted.id == created.id
assert deleted.deleted is True
@pytest.mark.skip(
reason="stage red: product gap, vector store search 500s (asearch TypeError) on missing query instead of 400"
)
@pytest.mark.parametrize("prefix", ["/v1", ""])
@pytest.mark.covers("llm.vector_stores.openai.input_validation.nonstream.works")
def test_search_missing_query_returns_error(self, proxy: ProxyClient, resources: ResourceManager) -> None:
key = resources.key()
created = unwrap(
proxy.transport.post(
"/v1/vector_stores",
headers=proxy.transport.bearer(key),
json=VectorStoreCreateBody(name=f"e2e-vs-search-{unique_marker()}"),
response_type=VectorStoreObject,
)
)
_delete_store_later(proxy, resources, key, created.id)
def test_search_missing_query_returns_error(self, proxy: ProxyClient, scoped_key: str, prefix: str) -> None:
result = proxy.transport.send(
f"/v1/vector_stores/{created.id}/search",
headers=proxy.transport.bearer(key),
f"{prefix}/vector_stores/vs_query_validation/search",
headers=proxy.transport.bearer(scoped_key),
json=VectorStoreSearchBody(max_num_results=10),
)
assert_client_error(result, "vector store search missing query")
assert result.status_code == 400, result.body
assert "query is required" in result.body
@pytest.mark.covers("llm.vector_stores.openai.basic.nonstream.works")
def test_file_attach_poll_and_search(self, proxy: ProxyClient, resources: ResourceManager) -> None:

View file

@ -1,5 +1,6 @@
import json
from datetime import datetime, timezone
from typing import Final
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
@ -3556,3 +3557,22 @@ def test_vector_store_search_rejects_caller_embedding_selection_params(blocked_k
assert response.status_code == 400, response.json()
assert blocked_key in str(response.json())
@pytest.mark.parametrize("prefix", ["/v1", ""])
def test_vector_store_search_missing_query_returns_400(prefix: str) -> None:
from fastapi import FastAPI
from fastapi.testclient import TestClient
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
from litellm.proxy.vector_store_endpoints.endpoints import router
app: Final = FastAPI()
app.include_router(router)
app.dependency_overrides[user_api_key_auth] = lambda: UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
response: Final = TestClient(app, raise_server_exceptions=False).post(
f"{prefix}/vector_stores/documents/search", json={"max_num_results": 2}
)
assert response.status_code == 400, response.text
assert "query" in response.text