Skip to content

Commit fffd60e

Browse files
committed
fix(batch): set has_errors on per-object/reference errors in stream recv
In _BatchBaseSync/_BatchBaseAsync.__recv, each failed object or reference from the server was wrapped in a fresh BatchObjectReturn/BatchReferenceReturn with only `errors` set. has_errors defaults to False on the dataclass and __add__ only ORs it forward (`self.has_errors or other.has_errors`), so it never became True even though `errors` was non-empty. This meant `if result.has_errors:` never fired on data.ingest() (and on batch.stream(), though failed_objects/failed_references were populated correctly there since those are tracked separately). Fixes #2107
1 parent ae327ca commit fffd60e

3 files changed

Lines changed: 45 additions & 0 deletions

File tree

mock_tests/test_batch.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,44 @@ def test_ssb_canceled_stream(
6060
for i in range(HOW_MANY):
6161
batch.add_object({"name": f"Object {i}"})
6262
assert len(service.uuids) == HOW_MANY
63+
64+
65+
class MockFailedObjectWeaviateService(weaviate_pb2_grpc.WeaviateServicer):
66+
def BatchStream(
67+
self,
68+
request_iterator: Generator[batch_pb2.BatchStreamRequest, None, None],
69+
context: grpc.ServicerContext,
70+
) -> Generator[batch_pb2.BatchStreamReply, None, None]:
71+
yield batch_pb2.BatchStreamReply(started=batch_pb2.BatchStreamReply.Started())
72+
for request in request_iterator:
73+
if request.HasField("data"):
74+
uuids = [obj.uuid for obj in request.data.objects.values]
75+
yield batch_pb2.BatchStreamReply(
76+
results=batch_pb2.BatchStreamReply.Results(
77+
errors=[
78+
batch_pb2.BatchStreamReply.Results.Error(
79+
uuid=uuid, error="mock failure"
80+
)
81+
for uuid in uuids
82+
]
83+
)
84+
)
85+
if request.HasField("stop"):
86+
return
87+
88+
89+
@pytest.fixture(scope="function")
90+
def failed_object_stream(
91+
canceled_stream_client: weaviate.WeaviateClient, start_grpc_server: grpc.Server
92+
):
93+
service = MockFailedObjectWeaviateService()
94+
weaviate_pb2_grpc.add_WeaviateServicer_to_server(service, start_grpc_server)
95+
return canceled_stream_client.collections.use(mock_class["class"])
96+
97+
98+
def test_ingest_has_errors_on_failed_object(
99+
failed_object_stream: weaviate.collections.Collection,
100+
):
101+
result = failed_object_stream.data.ingest([{"name": "Object 1"}])
102+
assert result.has_errors is True
103+
assert len(result.errors) == 1

weaviate/collections/batch/async_.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ async def __recv(self) -> None:
407407
result_objs += BatchObjectReturn(
408408
_all_responses=[err],
409409
errors={cached.index: err},
410+
has_errors=True,
410411
)
411412
failed_objs.append(err)
412413
logger.warning(
@@ -428,6 +429,7 @@ async def __recv(self) -> None:
428429
)
429430
result_refs += BatchReferenceReturn(
430431
errors={cached.index: err},
432+
has_errors=True,
431433
)
432434
failed_refs.append(err)
433435
logger.warning(

weaviate/collections/batch/sync.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ def __recv(self) -> None:
365365
result_objs += BatchObjectReturn(
366366
_all_responses=[err],
367367
errors={cached.index: err},
368+
has_errors=True,
368369
)
369370
failed_objs.append(err)
370371
logger.warning(
@@ -387,6 +388,7 @@ def __recv(self) -> None:
387388
failed_refs.append(err)
388389
result_refs += BatchReferenceReturn(
389390
errors={cached.index: err},
391+
has_errors=True,
390392
)
391393
logger.warning(
392394
{

0 commit comments

Comments
 (0)