Repository navigation
Add a distinct exception for generative query failures - #2210
karthiksenv wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Orca Security Scan Summary
| Status | Check | Issues by priority | |
|---|---|---|---|
| Infrastructure as Code | View in Orca | ||
| SAST | View in Orca | ||
| Secrets | View in Orca | ||
| Vulnerabilities | View in Orca |
|
To avoid any confusion in the future about your contribution to Weaviate, we work with a Contributor License Agreement. If you agree, you can simply add a comment to this PR that you agree with the CLA so that we can merge. |
|
I agree to the Weaviate Contributor License Agreement. The Main CI workflow is awaiting maintainer approval. Could a maintainer approve the workflow and review this PR? The local Linux unit/mock suite passed with 646 tests passing and 1 skipped, and the before/after behavior was verified against Weaviate 1.39.7 for both sync and async clients. |
|
@dirkkul, could you review this generative-query exception change or route it to the appropriate reviewer? The CLA acknowledgment and local validation are documented above. Please also confirm whether any fork CI approval or additional checks are needed before merge. |
|
@dirkkul, could you review the generative-query exception contract or route it to the Python client reviewer? The new exception remains a subclass of WeaviateQueryError, preserving existing handlers. The CLA acknowledgment, 646-test Linux run, and real-server before/after checks are documented above. Could you also confirm whether the Main workflow still needs fork approval and what remains before merge? |
| """ | ||
|
|
||
| def __init__(self, message: str): | ||
| super().__init__(message, "GRPC generative search") |
There was a problem hiding this comment.
I think user code that checks a failed generate call stops matching after an upgrade, in two ways:
str(e)reads... protocol GRPC generative search failed ...instead of... protocol GRPC search failed ..., so a check like"GRPC search failed" in str(e)stops matchingtype(e) is WeaviateQueryErrorturns false, whileisinstancestill matches
could we keep "GRPC search" as the protocol here? WeaviateGenerativeQueryError already tells generate failures apart. We write the changelog from merged PRs, so could you note the type change in the PR description, and the text change if you keep it?
how I checked
With the mock server from your tests failing every search with INTERNAL generative provider failed, collection.generate.near_text(query="test", single_prompt="Summarize {text}") raises Query call with protocol GRPC search failed with message generative provider failed. on main, and Query call with protocol GRPC generative search failed with message generative provider failed. on this branch. e.message and e.error are generative provider failed on both. A test using pytest.raises(WeaviateQueryError, match="GRPC search") fails the same way. Searching the repo for "GRPC search" and type(e) is WeaviateQueryError outside weaviate/connect/v4.py only finds your new test, so nothing in the client itself breaks. If you keep the old text, the assertion at mock_tests/test_generative_errors.py:96 can check it like test_regular_query_error_is_unchanged does. RELEASING.md has the changelog step. Whoever releases lists the merged PRs and adds the relevant entries to docs/changelog.rst.
There was a problem hiding this comment.
I restored the GRPC search wording, so existing message checks still match. The new exception remains a subclass of WeaviateQueryError; exact checks like type(e) is WeaviateQueryError do change. Both integration tests now check the wording and base-class compatibility.
| error = cast(Call, e) | ||
| if error.code() == StatusCode.PERMISSION_DENIED: | ||
| raise InsufficientPermissionsError(error) | ||
| if request.HasField("generative"): |
There was a problem hiding this comment.
request.HasField("generative") picks the error class four times, here and in the WeaviateRetryError branch below, and twice in the async grpc_search. could we move that choice into one helper in v4.py?
def _search_error(request: search_get_pb2.SearchRequest, message: str) -> WeaviateQueryError:
if request.HasField("generative"):
return WeaviateGenerativeQueryError(message)
return WeaviateQueryError(message, "GRPC search")then each site is one line, raise _search_error(request, str(error.details())) from e here and raise _search_error(request, str(e)) from e in the retry branch. Plain search errors get from e too, which only changes their traceback wording. Keeping the four checks inline works too, so this isn't blocking from my side.
There was a problem hiding this comment.
Done. _search_error now selects the exception in both clients, including retry exhaustion. Permission errors are still handled first.
| ("near_media", {"media": "YXVkaW8=", "media_type": NearMediaType.AUDIO}), | ||
| ], | ||
| ) | ||
| async def test_generative_query_errors(search_service: SearchService, client, method, kwargs): |
There was a problem hiding this comment.
I think most of this file could be one integration test instead. With Configure.Generative.anyscale() and no API key, every generate call fails with "no api key found" before reaching Anyscale. You could check with collection_factory that generate.fetch_objects raises WeaviateGenerativeQueryError on both clients, and that a query with a bad filter still raises WeaviateQueryError itself.
Only the UNAVAILABLE retry and PERMISSION_DENIED mocks would stay, since a real server can't produce those on demand, so 4 cases instead of 36.
sketch
def test_generative_query_error(collection_factory: CollectionFactory) -> None:
collection = collection_factory(
properties=[Property(name="text", data_type=DataType.TEXT)],
generative_config=Configure.Generative.anyscale(), # no API key, so generation fails
)
collection.data.insert({"text": "hello"})
with pytest.raises(WeaviateGenerativeQueryError):
collection.generate.fetch_objects(single_prompt="Summarize {text}")
with pytest.raises(WeaviateQueryError) as exc:
collection.query.fetch_objects(filters=Filter.by_property("missing").equal(1))
assert type(exc.value) is WeaviateQueryError
@pytest.mark.asyncio
async def test_generative_query_error_async(async_collection_factory: AsyncCollectionFactory) -> None:
collection = await async_collection_factory(
properties=[Property(name="text", data_type=DataType.TEXT)],
generative_config=Configure.Generative.anyscale(),
)
await collection.data.insert({"text": "hello"})
with pytest.raises(WeaviateGenerativeQueryError):
await collection.generate.fetch_objects(grouped_task="Summarize")Both pass against Weaviate 1.39.0 with ENABLE_MODULES=generative-dummy,generative-anyscale, and the default CI server already enables generative-anyscale.
why each mock test can go or should stay
test_generative_query_errors(18): the integration test covers the class choice. The nine methods also check that each executor setsgenerative. If you want to keep that, run it with the sync client only, since both clients share the executors.test_generative_timeout_and_retries(8): onlyUNAVAILABLEreaches theWeaviateRetryErrorbranch, so keep that one. A serverDEADLINE_EXCEEDEDtakes the sameRpcErrorbranch asINTERNAL, and thekwargsparameter changes nothing ingrpc_search.test_generative_client_deadline(2): a client deadline also raises anRpcErrorand takes the same branch, and each case waits out the 1 s query timeout.test_generative_validation_is_unchanged(2): validation runs before any request is sent.test_regular_query_error_is_unchanged(2): the plain query in the integration test covers it.test_generative_permissions_are_unchanged(2): keep it. It checks that the permission check still runs beforeHasField, and no integration test covers permissions on generate.test_successful_generative_query(2): the success path is unchanged.
There was a problem hiding this comment.
I moved the main checks into sync and async integration tests using Anyscale without an API key, and kept just the four retry and permission mock cases. All four mock cases pass, and both integration tests pass against Weaviate 1.39.7.
|
Hi @dirkkul and @tsmith023, I’ve addressed the three review comments in The four mock cases pass, and both integration tests pass against Weaviate 1.39.7. Lint and formatting checks pass too. Could you approve the pending CI workflow and take another look? If everything looks good and the required checks pass, I’d appreciate your approval and a merge. I’m happy to make any final adjustments. Thanks! |
Generative-query failures currently raise the same
WeaviateQueryErroras ordinary searches, so applications cannot select RAG-specific troubleshooting by exception type.Add
WeaviateGenerativeQueryErroras a subclass ofWeaviateQueryError. Sync and async gRPC searches select it when the request contains the generative field, including deadline expiry and exhausted retries. A shared_search_errorhelper selects the exception in both clients. Permission errors are handled before that selection.Compatibility: existing
except WeaviateQueryErrorhandlers andisinstance(e, WeaviateQueryError)checks still match. Exact checks such astype(e) is WeaviateQueryErrorno longer match failed generative requests; useisinstancewhen subclasses should match. The existingGRPC searcherror wording is preserved. Themessageanderrorattributes retain the original details, and exception chaining preserves the cause. Ordinary searches retain the generic exception.The exception identifies a failed generative request; retrieval can also fail, so it does not assume the provider caused the failure. The exception documentation includes a catch-order example and troubleshooting guidance.
Closes #818.
Validation of the current commit (
a22d4f3):generative-dummy,generative-anyscaleenabled and no provider API key. They check the specialized generative exception, compatibility with the base exception and existing error wording, and the exact generic exception for ordinary queries.git diff --checkpasses.Before the review follow-up, the full Linux unit/mock suite passed with 646 tests passing and 1 skipped. That earlier run covered the previous commit, not the revised test suite.