Skip to content

[Bugfix][NIXL] Fix multiple handles xfer race - #56104

Merged
NickLucche merged 5 commits into
vllm-project:mainfrom
mistralai:fix-multiple-handle-xfers
Sep 15, 2026
Merged

NickLucche merged 5 commits into
vllm-project:mainfrom
mistralai:fix-multiple-handle-xfers

Conversation

@NickLucche

Copy link
Copy Markdown
Member

A request can own multiple in-flight NIXL transfer handles (one per remote TP rank under heterogeneous TP).
On main, the first handle to reach ERR immediately invalidates the request's blocks and reports the failure to the scheduler, while the sibling handles may still be posting RDMA writes into those same blocks.
Posted transfers cannot be aborted, so once the scheduler reassigns the blocks, the in-flight writes corrupt whichever request owns them next.

This PR fixes this race by deferring NIXL receive-failure reporting and block invalidation until all transfers for the request have stopped, preventing in-flight RDMA writes from corrupting reused KV blocks.

Some cascading changes to keep purpose of data structures clear:

  • background threads use the existing _failed_recv_reqs Q to report failures
  • main engine thread failures are reported on _recv_failures set to minimize overhead
  • _failed_recv_reqs Q failures are addressed in get_finished; _pop_done_transfers also returns current poll failures, so we can track them and check whether all handles have been processed (or we delay, bulk of this PR)

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@NickLucche

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #87944 for commit 231c1deba790.

@njhill

njhill commented Sep 9, 2026

Copy link
Copy Markdown
Member

Thanks @NickLucche! I think this change may introduce some problems on the push side though, will add more detail soon.

@mergify

mergify Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @NickLucche.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@njhill njhill left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @NickLucche.

Also here are tests you could include to cover the push mode changes fixed by the inline suggestion: njhill@4143de0

Comment on lines +2785 to +2788
self,
req_id: str,
handle: int | None,
failed_req_ids: set[str] | None = None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
self,
req_id: str,
handle: int | None,
failed_req_ids: set[str] | None = None,
self, req_id: str, handle: int | None, failed_req_ids: set[str] | None = None

if not self._handle_failed_transfer(
request_id, handle, self._recv_failures
):
assert handle is not None

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: redundant assert

# writer thread also appends to it, so guard the pop.
with self._sending_transfers_lock:
done_pushing = self._pop_done_transfers(self._sending_transfers)
done_pushing, _ = self._pop_done_transfers(self._sending_transfers)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
done_pushing, _ = self._pop_done_transfers(self._sending_transfers)
done_pushing, failed_pushing = self._pop_done_transfers(
self._sending_transfers
)
# A failed send must never be reported as done: its blocks
# are freed via the lease / watchdog instead.
done_pushing = {
req_id
for req_id in done_pushing - failed_pushing
if req_id in self._recving_metadata
}

Otherwise failed sends could be reported as succesful (done_sending) and successful sends could complete early at write handle time bypassing the consumer notif accounting.

@NickLucche
NickLucche force-pushed the fix-multiple-handle-xfers branch from 231c1de to 551a9db Compare September 11, 2026 12:46
@NickLucche

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #88324 for commit 551a9dbbb59f.

@NickLucche

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #88336 for commit 47f5a96fb6cd.

@NickLucche
NickLucche force-pushed the fix-multiple-handle-xfers branch from 47f5a96 to c551acb Compare September 11, 2026 13:56
@NickLucche

Copy link
Copy Markdown
Member Author

/ci run

@NickLucche

Copy link
Copy Markdown
Member Author

Thanks for reviewing @njhill , added your push fix

@njhill njhill left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @NickLucche

@njhill

njhill commented Sep 11, 2026

Copy link
Copy Markdown
Member

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #88377 for commit c551acbea2d5.

@mergify

mergify Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @NickLucche.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Sep 12, 2026
Comment on lines +491 to +493
if handle is not None and not self._handle_failed_transfer(
request_id, handle, self._recv_failures
):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if handle is not None and not self._handle_failed_transfer(
request_id, handle, self._recv_failures
):
if not self._handle_failed_transfer(
request_id, handle, self._recv_failures
):
assert handle is not None

@NickLucche my bad I think this was my incorrect prior suggestion. This should fix the test ^^

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have pushed this but don't have permission for your branch.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@njhill sorry about that, I'll look into branch permissions

NickLucche and others added 5 commits September 14, 2026 12:39
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>
In get_finished, filter popped write-transfer req_ids against
failed_pushing and _recving_metadata: a failed send must never be
reported as done (its blocks are freed via the lease / watchdog), and
a successful send still waits for the consumer notification instead of
completing at write-handle time.

Also apply review nits (collapse _handle_failed_transfer signature,
drop the redundant assert in pull_worker by folding the handle check
into the condition) and adapt two tests from njhill's review branch
covering the failed-send and consumer-notif cases.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>

Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>

Co-authored-by: Nick Hill <nickhill123@gmail.com>
Always record setup failures, including when make_prepped_xfer raises before returning a handle. Retain a handle only when releasing it fails.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>
Assert delayed receive failures through get_transfer_results, initialize the push stub for direct receive synchronization, and keep the upstream push failure test consistent with the reviewed lease/watchdog behavior.

Validation: all 48 push tests and five focused receive lifecycle tests pass; pre-commit passes on all five PR files. The setup-failure test is blocked on macOS because CPU_ATTN rejects its block size of 16.

Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>
@NickLucche
NickLucche force-pushed the fix-multiple-handle-xfers branch from c551acb to 7ce48f9 Compare September 14, 2026 11:08
@NickLucche

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #88801 for commit 7ce48f91b922.

@NickLucche
NickLucche enabled auto-merge (squash) September 14, 2026 12:30
@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Sep 14, 2026
@mergify mergify Bot removed the needs-rebase label Sep 14, 2026
@njhill

njhill commented Sep 14, 2026

Copy link
Copy Markdown
Member

/ci run

@github-actions

Copy link
Copy Markdown

✅ CI is already running for this commit: https://buildkite.com/vllm/ci/builds/88801

@njhill

njhill commented Sep 14, 2026

Copy link
Copy Markdown
Member

Not sure what is going on with the CI here :(

@njhill

njhill commented Sep 15, 2026

Copy link
Copy Markdown
Member

/ci cancel

@njhill

njhill commented Sep 15, 2026

Copy link
Copy Markdown
Member

/ci run --allow-stale

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #89004 for commit 7ce48f91b922.

⚠️ This PR is 52 commits behind upstream main. Running CI at your own risk because --allow-stale was requested; outdated CI configuration may cause failures. Before merging, merge or rebase onto the latest main, then rerun /ci run on the latest PR commit.

@NickLucche
NickLucche merged commit 45779ef into vllm-project:main Sep 15, 2026
53 of 54 checks passed
ItsRoy69 pushed a commit to ItsRoy69/vllm that referenced this pull request Sep 15, 2026
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>
Co-authored-by: Nick Hill <nickhill123@gmail.com>
keneoneth pushed a commit to keneoneth/vllm that referenced this pull request Sep 16, 2026
Signed-off-by: NickLucche <nicolo.lucchesi@mistral.ai>
Co-authored-by: Nick Hill <nickhill123@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working kv-connector ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants