Conversation
__send_batch built the wholesale-failure error map with chunk-local enumerate() keys while BatchObjectReturn.__add__ merges with dict.update, so keys from separate chunks collided and failures were dropped or attributed to the wrong input object.
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. |
Author
|
I have read and I agree with the Contributor License Agreement. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Client-side batching reports fewer object failures than actually occur, and can attribute them
to the wrong input rows.
The wholesale-failure handler in
_BatchBase.__send_batchkeyed its error map by the positioninside the chunk being sent:
but
BatchObjectReturn.__add__merges chunk results with a plaindict.updateand does nore-keying (
classes/batch.py:231). Withbatch_sizesmaller than the number of objects, everychunk contributes keys
0..len(chunk)-1, so later chunks overwrite earlier ones.This contradicts the documented contract on
BatchObjectReturn("The keys of the
errorsanduuidsdictionaries will always be equivalent to theoriginal_indexof the objects as you added them to the batching loop") and every other failuresite in the same flow, which already uses the global index (
grpc_batch.py:157,sync.py:367,sync.py:410,async_.py:409,async_.py:452).Observed on
main@142d798, four objects withfixed_size(batch_size=2), both chunks rejected:The sharper variant is a successful chunk followed by a wholesale failure:
uuidskeys[0, 1]and
errorskeys[0, 1]end up describing different objects, so a caller that retries"the failed indices" re-sends rows that already landed and skips rows that did not.
Fixes #2165.
Change
BatchObject.indexis a requiredintassigned once in_add_object(base.py:826) and is notreset by
flush(), so it is always present and stable across retries. Chunks are popped underself.__lock, so no object can appear in two in-flight chunks and produce a duplicate key.Why the references sibling is untouched
The next handler down,
errors_ref = {idx: ... for idx, ref in enumerate(refs)}, looks like thesame bug and I deliberately left it alone.
BatchReferenceReturn.__add__merges with an offset(
classes/batch.py:293-299):That arithmetic expects dense, chunk-local keys: two chunks of two currently produce
{0: ref0, 1: ref1, 2: ref2, 3: ref3}. Switching it toref.indexwould yield{0, 1, 4, 5}—indices 2 and 3 would vanish and keys past the end would appear. Verified by running the two
merge paths. References do have an index problem, but it comes from elsewhere (the REST
referencespath returns sparse chunk-local keys, and the non-wholesale handlers feedalready-global keys into this offset merger), so it needs its own change rather than a symmetric
edit here.
Verification
One venv, Python 3.11.15,
-e .plusrequirements-devel.txtandrequirements-test.txt; everycommand run identically on
main@142d798as a control.python -m pytest mock_tests/ test/ -q2 failed, 556 passed, 1 skipped— both failures are the new tests558 passed, 1 skippedmock_tests/test_batch_error_indices.pydrives the real client against a mock gRPCservice, no network and no server:
test_wholesale_failed_chunks_report_every_object— asserts all four indices appear andthat each key describes the object it names, plus
len(failed_objects) == len(errors)test_failed_and_successful_chunks_do_not_share_keys— the uuid/error overlap abovetest_successful_chunks_keep_original_indices— passes on base too; it pins the conventionthe fix aligns to rather than testing the fix
python -m ruff check weaviate test mock_tests→ all checks passedpython -m ruff format --check weaviate test mock_tests→421 files already formatted(420 on base, so the new file is clean under the CI command at
.github/workflows/main.yaml:50)python -m flake8on both changed files → cleanintegration/,embedded/,journey/andtest-packageneed Docker and a realWeaviate;
pyrightis not installed in this venv. A repo-wide grep found no test asserting theold chunk-local behaviour, but those gates are CI's to judge.
One known knock-on, left alone deliberately
base.py:716-720filters the deprecatedall_responseslist by position(
enumerate(all_responses)) againstreadded_objects, which holds global-index objects. Underthe old keys that filter matched by accident; with correct keys a retried chunk keeps its
re-added objects instead of dropping them. That attribute is deprecated and emits a warning on
access, and the same mismatch already exists on the main
grpc_batch.pypath (:143isposition-indexed while
:157usesobj.index), so widening scope here would be a second,separate change. Flagging it so it is not mistaken for an oversight.
Disclosure: prepared with an AI coding assistant. Every number above comes from a command run
against
main@142d798, repeated on the unpatched tree with the identical command line so thedelta is checkable. The references analysis in particular was checked by executing both merge
strategies, not by reading them.