Skip to content

fix: surface a deterministic exception from ParallelWorker on concurrent failures#6469

Open
DABH wants to merge 1 commit into
google:mainfrom
DABH:parallel-worker-deterministic-errors
Open

fix: surface a deterministic exception from ParallelWorker on concurrent failures#6469
DABH wants to merge 1 commit into
google:mainfrom
DABH:parallel-worker-deterministic-errors

Conversation

@DABH

@DABH DABH commented Jul 24, 2026

Copy link
Copy Markdown

Describe the bug

asyncio.wait returns completed tasks as an unordered set. _ParallelWorker._run_impl iterates that set directly to decide which failed branch's exception to raise, so when two or more branches fail within the same wake-up, the surfaced exception depends on set iteration order (object-hash dependent). Failure output then differs between runs - and between record and replay for embedders that resume or replay agent workflows - and RetryConfig.exceptions (which filters retries by exception type name) can make a different retry decision on each execution of the same failure.

Describe the fix

Iterate completed tasks in input-index order (the _worker_index already stored on each task) when scanning for failures, so the lowest-index failed branch's exception is surfaced consistently. Behavior is otherwise unchanged.

Testing plan

New regression test tests/unittests/workflow/test_workflow_parallel_worker.py::test_parallel_worker_simultaneous_failures_raise_lowest_index: two branches that both fail immediately, run 10×, asserting the propagated exception is always the lowest-index item's. It fails roughly half the time without the fix and always passes with it.

$ pytest tests/unittests/workflow/
676 passed, 11 skipped, 10 xfailed in 6.73s

All pre-commit hooks pass. Related (same determinism theme, independent change): #6468.

@google-cla

google-cla Bot commented Jul 24, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Jul 24, 2026
…ent failures

asyncio.wait returns completed tasks as an unordered set. _ParallelWorker
iterated that set directly to pick the exception to raise, so when two or
more branches failed within the same wake-up, which branch's exception
surfaced depended on set iteration order (object-hash dependent). This made
failure output differ between runs — and between record and replay for
frameworks that resume or replay agent workflows and filter retries by
exception type (RetryConfig.exceptions).

Iterate completed tasks in input-index order instead, so the lowest-index
failed branch's exception is surfaced consistently. Behavior is otherwise
unchanged.

The regression test fails ~50% of the time without the fix (two branches
failing in the same wake-up) and always passes with it.
@DABH
DABH force-pushed the parallel-worker-deterministic-errors branch from cf84e6b to 93d0bb3 Compare July 24, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants