Skip to content

fix(sc): pass refit_payload_mode when recovery regenerates refit info - #4233

Merged
terrykong merged 1 commit into
mainfrom
fix/sc-collective-recovery-refit-payload-mode
Sep 22, 2026
Merged

terrykong merged 1 commit into
mainfrom
fix/sc-collective-recovery-refit-payload-mode

Conversation

@asolergi-nv

Copy link
Copy Markdown
Contributor

What does this PR do ?

Fixes the fleet-health recovery on the collective (nccl) refit transport: reconcile_communicator() called Policy.prepare_refit_info() without the refit_payload_mode that #3739 made mandatory, so every recovery died with a TypeError before touching NCCL.

Why it happened

It surfaced in the fault-injection validation of #3929 — see #3929 (comment) (attribution to #3739/#3592) and the run details in #3929 (comment) (CW-DFW job 18689836: step 3/24, one generation shard killed, then):

CollectiveWeightSynchronizer.reconcile_communicator()
  state_dict_info = self._policy.prepare_refit_info()
TypeError: Policy.prepare_refit_info() missing 1 required keyword-only argument: 'refit_payload_mode'

Effect on main since Sept 14: on the default transport, a run that loses a generation shard ends in the rebuild that was meant to keep it alive (#3591's contract). nccl_reshard is unaffected — its rebuild does not re-prepare refit info — which is why the reshard step-kill scenario in that validation passed while the nccl one and the Gym quarantine one failed.

The fix

  • nemo_rl/weight_sync/collective_weight_synchronizer.py: the rebuild now mirrors init_communicator — self._policy.prepare_refit_info(refit_payload_mode=self._generation.get_refit_payload_mode()). get_refit_payload_mode is on GenerationInterface (default "hf_export", overridden by MegatronGeneration), so this is valid for every backend the collective synchronizer can hold.
  • tests/unit/weight_sync/test_reconcile_communicator.py: the fake policy is now keyword-only, exactly like Policy.prepare_refit_info, so the signature is pinned — against the old call, 14 of the 38 tests in the file fail with the production error. The fake generation answers get_refit_payload_mode, and a new test_refit_info_is_regenerated_in_the_backend_s_payload_mode asserts the rebuild asked for the backend's mode and pushed the metadata to the fleet once.

Issues

No standalone issue; raised in #3929 (comment). #3929 should re-merge main after this lands and re-run its collective-transport scenarios.

Usage

Not applicable — no user-facing change. To exercise the fixed path end to end on a node with ≥ 3 GPUs:

# default transport (nccl): kills one generation shard at a step boundary and expects the run to
# complete on the survivor. Before this fix it dies at the first rebuild with the TypeError above.
bash tests/functional/grpo_sc_generation_shard_recovery.sh

Before your PR is "Ready for review"

Pre checks:

  • Make sure you read and followed Contributor guidelines
  • Did you write any new necessary tests?
  • Did you run the unit tests and functional tests locally? Visit our Testing Guide for how to run tests — unit: 1420 passed across tests/unit/weight_sync, tests/unit/single_controller, tests/unit/models/generation/test_fleet_health.py, tests/unit/models/policy/test_worker_refit_signatures.py, tests/unit/models/policy/test_lm_policy_collective.py. Functional: the recovery variant above needs ≥ 3 GPUs and was not run locally; it is the run that found the bug.
  • Did you add or update any necessary documentation? — none needed; behaviour is what the design docs already describe.

Additional Information

  • The nccl_reshard mid-refit stall reported in the same validation (reshard-refit-kill / reshard-refit-freeze) is a different problem — a timing race between the controller's refit bound and the synchronizer's straggler settle — and is not addressed here.

🤖 Generated with Claude Code

Policy.prepare_refit_info has taken a keyword-only refit_payload_mode since
#3739 (5d49fbf, 2026-09-11), which updated the one caller that existed at
the time: CollectiveWeightSynchronizer.init_communicator. #3592 (53bce05,
2026-09-14) then added a second caller in reconcile_communicator -- the
fleet-health recovery that rebuilds the communicator over the surviving shards
and redistributes refit metadata to them -- written against the pre-#3739
signature. The merge was clean textually and wrong semantically: every
collective-transport recovery raised

    TypeError: Policy.prepare_refit_info() missing 1 required keyword-only
    argument: 'refit_payload_mode'

before touching NCCL, so a run that lost a generation shard died in the
rebuild that was meant to keep it alive. nccl_reshard is unaffected: its
rebuild does not re-prepare refit info.

Nothing was red. The unit fake for the policy accepted a bare call, every
fleet-health recovery variant self-skips on CI's 2-GPU runners, and the last
cluster runs of those variants predate the sync that brought #3739 in. Found
by the fault-injection validation on #3929 (CW-DFW job 18689836):
#3929 (comment)

Mirror init_communicator's call, asking the backend for its payload mode. Make
the test fake keyword-only so the signature is pinned -- against the old call
14 of the 38 reconcile tests now fail with the production error -- and add a
test that the rebuild asks for the backend's mode and pushes the metadata once.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: asolergibert <asolergibert@nvidia.com>
@asolergi-nv asolergi-nv added the CI:L0 Run doctests and unit tests label Sep 21, 2026
@copy-pr-bot

copy-pr-bot Bot commented Sep 21, 2026

Copy link
Copy Markdown

Auto-sync is disabled for ready for review pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@asolergi-nv
asolergi-nv requested review from a team as code owners September 21, 2026 15:24
@asolergi-nv

Copy link
Copy Markdown
Contributor Author

/ok to test 3d4701f

@terrykong terrykong left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@youngeunkwon0405 to review (this pr should target yours)

@youngeunkwon0405

Copy link
Copy Markdown
Contributor

@youngeunkwon0405 to review (this pr should target yours)

Hi @terrykong, why does this PR have to target #3929? This is just fixing the previous implementation. Shouldn't it be more natural to go right into main?

@terrykong

Copy link
Copy Markdown
Collaborator

@youngeunkwon0405 sorry, it was my confusion. i thought it was tied

@terrykong
terrykong merged commit 592149e into main Sep 22, 2026
69 checks passed
@terrykong
terrykong deleted the fix/sc-collective-recovery-refit-payload-mode branch September 22, 2026 17:33
yfw added a commit that referenced this pull request Sep 23, 2026
Brings #4198 (remove the DTensor v1 policy worker), #4207, #4196, #4143
(MiniMax-M3 GRPO support), #4233, #4232 and #3408 (flow_grpo research).

Conflicts and resolution:
- pyproject.toml: main removed the `fsdp` extra together with the v1 worker;
  this branch had given that extra its own torch 2.13 pin. The extra is
  dropped here as well (with its `[tool.uv] conflicts` entries), and the
  per-extra torch comment no longer lists it.
- uv.lock: regenerated from this branch's lock; the only change is the
  addition of #3408's flow-grpo research dependencies (albumentations,
  paddleocr, scikit-image, ...). No existing package moved, and nothing
  resolves below main except the deliberate numpy / llguidance / flash-attn
  pins.

Also removed, not conflicting: `_patch_vllm_minimax_m3_topk_buffer_layout`
(#4143) and its tests. It backported vllm-project/vllm@d1a8ba63 (token-major
vs head-major `topk_indices_buffer`) onto vLLM 0.26.0 and its docstring asks
for removal at vLLM >= 0.27; vLLM 0.29.0's `minimax_m3/common/indexer.py`
already carries the head-major `buf_htk` layout, so on this branch the patch
could only ever log "source shape not found" and its installed-vLLM anchor
tests would fail.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yi-Fu Wu <yifu.wu@gmail.com>
@yfw yfw mentioned this pull request Sep 23, 2026
4 tasks done
cspades pushed a commit that referenced this pull request Sep 24, 2026
…#4233)

Signed-off-by: asolergibert <asolergibert@nvidia.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI:L0 Run doctests and unit tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants