Skip to content

ci: authenticate HuggingFace model prefetch to avoid rate limits - #1948

Merged
NirWolfer merged 1 commit into
ai-dynamo:mainfrom
NirWolfer:ci/hf-token-rate-limit-fix
Jul 27, 2026
Merged

NirWolfer merged 1 commit into
ai-dynamo:mainfrom
NirWolfer:ci/hf-token-rate-limit-fix

Conversation

@NirWolfer

@NirWolfer NirWolfer commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What?

The shared CI egress was being rate-limited by HuggingFace on anonymous requests, causing the vLLM and SGLang sanity stages to fail during Qwen/Qwen3-8B prefetch.

Bind the svc-nixl-hf-token Jenkins secret text credential as HF_TOKEN in the build-wheel pipeline and pass it through to the sanity testScript so snapshot_download authenticates rather than hitting the anonymous rate limit.

Why?

rate limit failing build-wheel pipeline on rare occasions

How?

It is optional, but for complex PRs, please provide information about the design,
architecture, approach, etc.

Summary by CodeRabbit

  • Bug Fixes

    • Improved vLLM and SGLang aarch64 CI sanity checks by routing model prefetch through an internal Hugging Face mirror endpoint when provided.
    • Increased prefetch reliability by extending Hugging Face metadata/download timeouts during the CI sanity prefetch flow.
  • Documentation

    • Updated the CI overview to clarify dispatcher-triggered sanity prefetch uses the internal mirror (not huggingface.co) and how the mirror endpoint is supplied to the SLURM sanity container.

@NirWolfer
NirWolfer requested review from a team as code owners July 15, 2026 13:12
@github-actions

Copy link
Copy Markdown

👋 Hi NirWolfer! Thank you for contributing to ai-dynamo/nixl.

Your PR reviewers will review your contribution then trigger the CI to test your changes.

🚀

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Jenkins configures an internal Hugging Face mirror for vLLM and SGLang sanity containers. The prefetch script sets longer Hugging Face Hub timeouts, and CI documentation describes the endpoint propagation.

Changes

Hugging Face sanity prefetch

Layer / File(s) Summary
Endpoint propagation and sanity execution
.ci/jenkins/lib/build-wheel-matrix.yaml
Defines SANITY_HF_ENDPOINT and passes it as HF_ENDPOINT to the vLLM and SGLang SLURM sanity commands.
Prefetch timeout configuration and documentation
.gitlab/test_vllm_sglang_sanity.sh, .ci/docs/ci-overview.md
Exports 86400-second Hugging Face Hub metadata and download timeouts, while documenting the internal mirror and endpoint flow.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: pvijayakr

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the PR's goal of improving HuggingFace prefetch behavior to reduce rate-limit failures.
Description check ✅ Passed The description includes the required What and Why sections, with the optional How section left blank.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.ci/jenkins/lib/build-wheel-matrix.yaml:
- Around line 79-80: Restrict the HF_TOKEN binding from the top-level wheel job
credentials to only the vLLM/SGLang sanity steps in the matrix. Update the
relevant sanity-step wrapper or invocation so the token is available there while
remaining unavailable to build and image stages that execute PR-controlled code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 0320dcd5-72f6-4a52-9d9e-f9444166d13c

📥 Commits

Reviewing files that changed from the base of the PR and between 22cdab3 and bd426fa.

📒 Files selected for processing (3)
  • .ci/docs/ci-overview.md
  • .ci/jenkins/lib/build-wheel-matrix.yaml
  • .gitlab/test_vllm_sglang_sanity.sh

Comment thread .ci/jenkins/lib/build-wheel-matrix.yaml Outdated
@NirWolfer
NirWolfer force-pushed the ci/hf-token-rate-limit-fix branch from bd426fa to d3d8f6e Compare July 20, 2026 11:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.ci/docs/ci-overview.md (2)

30-35: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the Jenkins job count.

This note says there are 13 jobs (the dispatcher, 7 children, and 5 standalone jobs), but Line 140 still says 12. Update the later count so the overview is consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.ci/docs/ci-overview.md around lines 30 - 35, Update the Jenkins job count
in the later overview section to 13, keeping it consistent with the breakdown
documented in the note and leaving the job descriptions unchanged.

170-170: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add blank lines before these headings.

Insert a blank line before the headings on Line 170 and Line 175 to satisfy Markdownlint MD022.

Also applies to: 175-175

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.ci/docs/ci-overview.md at line 170, Insert a blank line immediately before
the `nixl-ci-build-container-pr` heading and the other heading at the referenced
later location, preserving their content and satisfying Markdownlint MD022.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.ci/docs/ci-overview.md:
- Around line 30-35: Update the Jenkins job count in the later overview section
to 13, keeping it consistent with the breakdown documented in the note and
leaving the job descriptions unchanged.
- Line 170: Insert a blank line immediately before the
`nixl-ci-build-container-pr` heading and the other heading at the referenced
later location, preserving their content and satisfying Markdownlint MD022.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 0bebbed7-237c-4854-beee-cb8f01f91dc1

📥 Commits

Reviewing files that changed from the base of the PR and between bd426fa and d3d8f6e.

📒 Files selected for processing (3)
  • .ci/docs/ci-overview.md
  • .ci/jenkins/lib/build-wheel-matrix.yaml
  • .gitlab/test_vllm_sglang_sanity.sh

@NirWolfer

Copy link
Copy Markdown
Contributor Author

/build

@NirWolfer
NirWolfer requested a review from dpressle July 20, 2026 11:43
@NirWolfer
NirWolfer force-pushed the ci/hf-token-rate-limit-fix branch from d3d8f6e to 687b5ad Compare July 20, 2026 13:16
@pull-request-size pull-request-size Bot added size/M and removed size/S labels Jul 20, 2026
@NirWolfer

Copy link
Copy Markdown
Contributor Author

/build

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.ci/jenkins/lib/build-wheel-matrix.yaml:
- Around line 219-235: Remove the pipeline_start credential binding and global
env.HF_TOKEN assignment. Scope both credentials inside the vLLM/SGLang
sanity-step invocations, forwarding HF_ENDPOINT and HF_TOKEN only to those
commands while leaving later build scripts and Docker builds without token
access.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 8e810bf4-44b9-4966-b06c-d142f02479bb

📥 Commits

Reviewing files that changed from the base of the PR and between d3d8f6e and 687b5ad.

📒 Files selected for processing (3)
  • .ci/docs/ci-overview.md
  • .ci/jenkins/lib/build-wheel-matrix.yaml
  • .gitlab/test_vllm_sglang_sanity.sh

Comment thread .ci/jenkins/lib/build-wheel-matrix.yaml Outdated
@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-build-wheel · commit 7cb5f2e9

TL;DR: The SGLang sanity job failed because the model prefetch (snapshot_download('Qwen/Qwen3-8B')) got an HTTP 408 Request Timeout from the Artifactory HuggingFace proxy on model-00001-of-00005.safetensors; this is a transient infra/network error, not a code bug. Add retry/backoff (or max_workers=1 + HF_HUB_DOWNLOAD_TIMEOUT) around the prefetch so a single 408 doesn't kill the run.

Full analysis

Summary: Stage "Run SGLang sanity" (node 534) failed during model weight prefetch, not during NIXL/build logic.

Root cause: At 14:02:47 the script started snapshot_download('Qwen/Qwen3-8B'); ~18s later one shard download returned 408 Request Timeout from https://artifactory.nvidia.com/artifactory/api/huggingfaceml/huggingface-remote/.../model-00001-of-00005.safetensors, which huggingface_hub re-raised as LocalEntryNotFoundError, exiting the process (exit code 1). The failure was fast (no hang, no wall-clock kill) and originated from the upstream Artifactory HF proxy — a transient network/infrastructure error. The build itself, wheel repair, image build, and push all succeeded; the vLLM sanity path on the same commit passed.

Implicated commit: unknown — this is an environmental failure, not a code regression. (The prefetch script .gitlab/test_vllm_sglang_sanity.sh merely lacks retry hardening.)

File: .gitlab/test_vllm_sglang_sanity.sh:99 (the snapshot_download prefetch)

Suggested fix:

  1. Primary: Retry the build — a 408 from the proxy is transient and will likely pass on rerun.
  2. Harden the prefetch so a single transient 408 doesn't fail the job. Wrap the snapshot_download in a bash retry loop (e.g. 3–5 attempts with backoff), and/or set export HF_HUB_DOWNLOAD_TIMEOUT=60 and pass max_workers down. Example:
    for attempt in 1 2 3 4 5; do
      python3 -c "from huggingface_hub import snapshot_download; snapshot_download('${MODEL}', max_workers=4)" && break
      log "prefetch attempt ${attempt} failed; retrying in $((attempt*10))s"
      sleep $((attempt*10))
    done
  3. Separately, escalate the recurring 408s to whoever owns the Artifactory huggingface-remote mirror if they persist across retries.

Security note: The HF_TOKEN is passed in cleartext on the ssh/srun command line and is fully visible in the console log (in the slurm.run/srun argv lines). Treat that token as exposed and rotate it, and switch to injecting it via an env file or masked credential rather than an inline command-line argument.

Related: none found.

@NirWolfer
NirWolfer force-pushed the ci/hf-token-rate-limit-fix branch from 687b5ad to c38742e Compare July 22, 2026 10:53
@pull-request-size pull-request-size Bot added size/S and removed size/M labels Jul 22, 2026
@NirWolfer

Copy link
Copy Markdown
Contributor Author

/build

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitlab/test_vllm_sglang_sanity.sh:
- Around line 104-105: Update the HF_HUB_ETAG_TIMEOUT and
HF_HUB_DOWNLOAD_TIMEOUT defaults in the sanity-job environment setup to a
substantially smaller value bounded by the CI job budget, while preserving any
explicitly provided environment values and leaving retry behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b13a6a0b-126e-4adc-b128-cad8232c9715

📥 Commits

Reviewing files that changed from the base of the PR and between 687b5ad and c38742e.

📒 Files selected for processing (3)
  • .ci/docs/ci-overview.md
  • .ci/jenkins/lib/build-wheel-matrix.yaml
  • .gitlab/test_vllm_sglang_sanity.sh

Comment thread .gitlab/test_vllm_sglang_sanity.sh
@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-non-gpu · commit 2d277cdf

TL;DR: The "Test CPP" stage failed because ucx/TestErrorHandling.LoadRemoteThenFail/0 crashed with SIGSEGV during the UCX error-handling test that tears down the target agent while a transfer is in flight; this is a backend crash unrelated to PR #1948 (which only touches HuggingFace CI auth) — most likely a pre-existing race/flake in the UCX disconnect path.

Full analysis

Summary: Jenkins stage "Test CPP" (node 462, x86_64/nixl-base-25.06-cuda12.9-ubuntu24.04) failed with exit code 245 because the gtest binary reported 1/154 failing: ucx/TestErrorHandling.LoadRemoteThenFail/0 killed by signal SIGSEGV (595 ms).

Root cause: A segmentation fault inside the UCX backend during the LOAD_REMOTE_THEN_FAIL scenario. That test path (test/gtest/error_handling.cpp, postXfer) calls m_Target.destroy() immediately after createXferReq and around postXferReq to simulate a remote-disconnect. The crash occurs in the UCX teardown/disconnect handling while the request is being posted — a race in the backend's endpoint error/cleanup path rather than in the test logic itself. Notably, gtest-parallel re-ran and the sibling XferThenFail/XferFailRestore/XferPostThenFail cases passed, so this presents as an intermittent (flaky) crash. It is not caused by PR #1948, whose only change is authenticating HuggingFace model prefetch in CI — completely unrelated to the UCX C++ transfer path.

Implicated commit: unknown — the crash is in the UCX backend disconnect path exercised by error_handling.cpp; not attributable to a commit in this PR (#1948, HuggingFace CI auth). The test itself was last significantly touched around the ownership/release fix noted in postXfer (lines 406–412).

File: test/gtest/error_handling.cpp:396-417 (the destroy-during-post sequence) exercising the UCX backend crash; underlying fault is in src/plugins/ucx endpoint disconnect handling.

Suggested fix: This is a backend crash unrelated to PR #1948, so re-running CI should unblock the PR. To fix the underlying flake, reproduce locally with gtest-parallel --repeat=N ./bin/gtest --gtest_filter='ucx/TestErrorHandling.LoadRemoteThenFail/0' (ideally under ASan, per PR #1709 sanitizer builds) to capture the stack, and harden the UCX backend's remote-disconnect/endpoint-cleanup path against use-after-free when an agent is destroyed while a transfer request is in flight. Do not merge #1948 on the assumption it caused this; instead file/track a separate bug against the UCX error-handling suite.

Related: PR #1948 (unrelated, HuggingFace CI auth); PR #1743 (run gtest in single process — may reduce cross-test interference); PR #1709 (ASan/UBSan/TSan builds, useful to root-cause this SIGSEGV).

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-dl-gpu-ep · commit 2d277cdf

TL;DR: The expansion_fault_contraction.json elastic EP test failed because, after rank 2 was intentionally killed in phase 2, the surviving ranks crashed with CUDA "illegal memory access" during dispatch/combine and exited with code 1 (not the tolerated -SIGTERM), so elastic.py flagged them as real failures. This is a fault-tolerance regression in the EP dispatch/combine path on the UCX v1.22.x build, where a peer disappearing mid-transfer triggers an illegal GPU memory access instead of graceful contraction.

Full analysis

Summary: Stage 220 "Run DL EP elastic tests" (UCX v1.22.x path) failed on plan expansion_fault_contraction.json; workers 1, 2, 3 exited with code 1.

Root cause: In phase 2 the plan [0, 1, -2, 3] deliberately kills rank 2 during a dispatch/combine. The surviving ranks (PIDs 4129106/07/08) then hit CUDA warning: an illegal memory access was encountered (function destroyEvent) and cuMemFree_v2 ... failed: an illegal memory access / cuStreamDestroy_v2 ... failed from UCX's cuda_ipc_ep.c and cuda_iface.c, i.e. the CUDA IPC endpoints/kernels touched memory belonging to the killed peer. Because those ranks aborted with exit code 1 (rather than 0 or -SIGTERM), the join loop at elastic.py:70 collected them as failures and main() raised RuntimeError at line 692. The killed rank itself behaved correctly (clean SIGTERM handler). Notably the ucx-master test path (stage 244) passed, so this is specific to the UCX 1.22.x runtime interacting with the EP CUDA-IPC teardown/fault path — the dispatch/combine kernels don't safely fence off a peer that vanishes mid-transfer.

Implicated commit: Not definitively pinpointable from logs alone. The most likely-related change is the low-latency NVLink / CUDA-IPC path work — [REDACTED:Hex High Entropy String] "nixl_ep: Optimize low-latency NVLink path (#1751)" (Itay Alroy) and 22cdab3de2e9 "PLUGINS/UCX: Added option to forcibly close UCP endpoints (#1846)" (Raul Akhmetshin), which affect exactly the CUDA-IPC endpoint teardown that faults here.

File: examples/device/ep/tests/elastic/elastic.py:70 (where the exit code is judged) surfaces it; the actual fault is in the EP dispatch/combine + CUDA-IPC teardown — examples/device/ep/csrc/kernels/* (nixl_ep_ll/ht) and UCX cuda_ipc_ep.c:51 / cuda_iface.c:371 reached via the UCX plugin.

Suggested fix: Make the EP dispatch/combine path fault-safe when a peer rank disappears mid-transfer on the UCX 1.22.x runtime: guard CUDA-IPC endpoint/stream/event destruction so a dead peer's mapping cannot cause an illegal memory access (e.g., validate/clear the peer's IPC handles before cuMemFree/cuStreamDestroy, and fence the combine kernel against removed ranks during contraction). Reproduce directly with timeout 300 python3 examples/device/ep/tests/elastic/elastic.py --plan .../expansion_fault_contraction.json --num-processes 4 ... --validate-phase-failures against the v1.22.x UCX build. As a short-term unblock, confirm whether #1751/#1846 introduced the teardown change and revert/patch that; do not merely widen the accepted exit codes in elastic.py, since that would mask a genuine survivor-rank GPU crash.

Related: #1751 (LL NVLink path), #1846 (forcibly close UCP endpoints); no existing issue matches the "illegal memory access" elastic-EP crash — consider filing one.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 0218b8cf-1031-4d94-b00c-1b79f66b31f6 in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit 2d277cdf

TL;DR: The Run Nixlbench tests stage (ucx-v1.22.x image) died with exit code 139 (SIGSEGV) when the UCCL / WRITE / VRAM→VRAM / ETCD nixlbench worker crashed during engine teardown ("Destroying Engine…"). This is the known, still-unfixed UCCL shutdown crash (PR #1724), not a regression from PR #1948; the fix is to land the UCCL crash fix or quarantine the UCCL nixlbench cases in CI.

Full analysis

Summary: Stage 337 "Run Nixlbench tests" failed because a nixlbench process crashed with SIGSEGV (srun exit code 139) during the UCCL backend WRITE/VRAM→VRAM ETCD run; stage 125 is just the pipeline stopping the parallel branch as a result.

Root cause: A segfault in the UCCL backend on the shutdown path. The log shows the benchmark completed and printed its result row (16384 … 0.036998 GB/Sec), then both workers entered teardown ("Waiting to accept…", "Destroying Engine…", "Stop background accept…") and one process crashed:

  • parallel: This job failed: … --backend UCCL --op_type WRITE --initiator_seg_type VRAM --target_seg_type VRAM …
  • srun: error: mizu01: task 0: Exited with exit code 139

This is a crash, not a wall-clock/hang issue — the log has continuous activity right up to the fault (no multi-minute gap). Note also that every UCCL run reports pathological bandwidth (~0.03 GB/s vs 2–5 GB/s for UCX) and the fault occurs during Destroying Engine, pointing squarely at the UCCL engine destruction/connection-teardown code. This matches the open, unmerged PR #1724 "UCCL crash Fix + GDB trap." The pin_thread_to_numa … Failed to set thread affinity to NUMA node 1 lines are benign environment warnings, not the cause.

Implicated commit: Not introduced by this PR. UCCL plugin last changed in [REDACTED:Hex High Entropy String] (2026-06-09, Colin Hirsch) and functionally in [REDACTED:Hex High Entropy String] (2026-05-26, Pravein Govindan Kannan, "Enable local xfer for UCCL backend"), both long before build #2869. The crash is a pre-existing UCCL defect.

File: src/plugins/uccl/uccl_backend.cpp (UCCL engine/connection destruction path exercised at "Destroying Engine…"); test driver benchmark/nixlbench UCCL cases.

Suggested fix: Land the UCCL crash fix from PR #1724 (fixes the SIGSEGV in UCCL engine teardown). As an immediate CI unblock, skip/quarantine the UCCL nixlbench backend cases (the loop that runs --backend UCCL for both ASIO and ETCD runtimes) so an unrelated PR like #1948 isn't blocked by this known-flaky backend. Re-run the build to confirm the failure is confined to UCCL. Core dumps are available per docs/DebugCoreDumps.md to get the exact stack.

Related: PR #1724 "UCCL crash Fix + GDB trap" (#1724); possibly related shutdown-race fix PR #1963 "NIXLBENCH: Fix race condition with ASIO runtime on shutdown" (merged 2026-07-21, #1963).

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id df4c190d-baa1-4f40-8468-234b0b6a8b32 in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-dl-gpu-ep · commit 2d277cdf

TL;DR: The nixl-ci-dl-gpu-ep build failed in the "Run DL EP elastic tests" stage (UCX v1.22.x variant): the expansion_fault_contraction.json test kills rank 2 mid-transfer, and the surviving ranks 0/1/3 then crash with a CUDA "illegal memory access" while tearing down CUDA-IPC endpoints to the dead peer, exiting with code 1 instead of a tolerated SIGTERM. Root cause is the EP fault-tolerance / UCX CUDA-IPC endpoint teardown not surviving a peer rank being killed on UCX 1.22.x.

Full analysis

Summary: Elastic EP fault-injection test (expansion_fault_contraction.json) fails on the UCX v1.22.x variant; surviving workers crash on peer removal with an illegal CUDA memory access.

Root cause: The plan intentionally kills rank 2 during phase-2 dispatch/combine ("[rank 2] Killing rank during dispatch/combine", "SIGTERM (15) received for process 51914"). When rank 2 dies, its CUDA-IPC / NVLINK-mapped peer memory becomes invalid. The surviving ranks (0, 1, 3) then hit CUDA warning: an illegal memory access was encountered (function destroyEvent) and UCX cuda_ipc_ep.c:51 cuMemFree_v2(...) failed / cuda_iface.c:371 cuStreamDestroy_v2(...) failed while destroying the NIXL_EP buffer (also emitting "destroy() was not called before NIXL_EP buffer destruction"). Because the survivors exit with code 1 (not 0 or -SIGTERM), main() in elastic.py (lines ~50–55) treats them as failed and raises RuntimeError. This is version-dependent: the ucx-master variant (stage 220) ran the same test and passed, so the CUDA-IPC endpoint teardown on peer-kill is not handled correctly with UCX 1.22.x. This is a genuine crash, not a wall-clock hang — log timestamps show continuous activity (13:09:09→13:09:27) with no gaps.

Implicated commit: Most likely 22cdab3de2e9 — "PLUGINS/UCX: Added option to forcibly close UCP endpoints." (Raul Akhmetshin, 2026-07-15), which changes UCP endpoint teardown behavior exercised when a peer rank is killed. The CUDA-IPC NVLINK path itself originates from [REDACTED:Hex High Entropy String] (Michal Shalev, "NIXL_EP: Enable CUDA IPC NVLINK backend", #1099). Confirm against the diff for PR #1948 under test.

File: src/plugins/ucx/ endpoint-close path (see UCX cuda_ipc_ep.c:51 / cuda_iface.c:371 errors surfaced via the UCX plugin) and the EP buffer destructor in examples/device/ep/csrc/ (the "destroy() was not called before NIXL_EP buffer destruction" warning). Test assertion at examples/device/ep/tests/elastic/elastic.py:50-55.

Suggested fix: Handle peer-kill CUDA-IPC teardown gracefully so surviving ranks don't dereference invalidated IPC memory: on detecting a removed/killed peer, close/unmap that peer's CUDA-IPC endpoint and skip cuMemFree/cuStreamDestroy on already-invalid device pointers (swallow CUDA_ERROR_INVALID_CONTEXT/illegal-access during destruction), and ensure destroy() is invoked before buffer teardown. Verify the new "forcibly close UCP endpoints" option (#1846) is actually engaged on the fault-contraction path for UCX 1.22.x. Do not raise the test timeout — this is a crash, not a slow run.

Related: PR #1846 (UCP forcible endpoint close), PR #1099 (CUDA IPC NVLINK backend), PR #1500 (planned SIGTERM handling in elastic test), PR #1953 (UCX version logging). No existing issue found for this exact illegal-memory-access-on-peer-kill signature — worth filing one.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 002d602b-b0a4-431e-adc6-ebf10abca781 in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-dl-gpu-ep · commit 2d277cdf

TL;DR: The expansion_fault_contraction elastic-EP test failed because, when rank 2 was intentionally killed mid dispatch/combine (phase 2), the surviving ranks (0,1,3) hit a CUDA "illegal memory access" in the high-throughput EP kernel and died with exit code 1 instead of timing out gracefully and cleaning up the failed peer — a regression in the ht dispatch/combine peer-fault path.

Full analysis

Summary: Stage 220 "Run DL EP elastic tests" (ucx-master variant) failed; the fault-tolerance plan [0,1,-2,3] killed rank 2 during dispatch/combine and the surviving ranks crashed with an illegal CUDA memory access rather than surviving the fault.

Root cause: In phase 2 the test expects the ht dispatch/combine kernel to detect the killed peer, hit the configurable GPU timeout (--timeout-ms 10000), set the mask buffer, and return so that query_mask_buffer/disconnect_ranks can clean up rank 2. Instead the surviving ranks dereferenced memory belonging to the dead rank's cuda_ipc mapping ("CUDA warning: an illegal memory access was encountered … cuMemFree_v2((CUdeviceptr)self->device_ep) / cuStreamDestroy_v2" from UCX cuda_ipc_ep.c), so test_main aborted with exit code 1 before reaching the mask-cleanup path. main() only tolerates -SIGTERM exits (the killed rank), so the exit-code-1 crashes of the survivors are reported as failures. Notably the ucx-v1.22.x parallel variant (stage 244) passed, so the regression is in how the ht kernel path handles a vanishing peer's IPC memory, exposed under ucx-master.

Implicated commit: [REDACTED:Hex High Entropy String] — "EXAMPLES/DEVICE/EP/CSRC: Removed extra params from ht functions. (#1812)", Raul Akhmetshin, 2026-07-22 (only recent change to examples/device/ep/csrc/kernels/nixl_ep_ht.cu, landed the same day as this build).

File: examples/device/ep/csrc/kernels/nixl_ep_ht.cu (ht dispatch/combine peer-fault/timeout handling); test driver examples/device/ep/tests/elastic/elastic.py:50 (only -SIGTERM is tolerated) with plan examples/device/ep/tests/elastic/expansion_fault_contraction.json:4 ([0, 1, -2, 3]).

Suggested fix: Review commit #1812: confirm the removed parameters to the ht dispatch/combine functions did not drop the peer/timeout/mask-status argument that lets a surviving rank bound its access to a peer that may have died. The ht kernel must bounds-check/guard remote cuda_ipc pointers and honor the GPU timeout so it returns and marks the peer failed instead of accessing freed IPC memory. As an interim step, run the elastic test against the exact ucx-master SHA to confirm the UCX-side cuda_ipc_ep teardown interaction, and add a targeted revert/patch of #1812's ht signature change if it removed the fault-handling param.

Related: PR #1812 (commit [REDACTED:Hex High Entropy String]); triggering PR #1948. Search the tracker for "elastic EP illegal memory access fault contraction" to correlate.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id a94b545f-e1b1-4cb7-b55b-e0ce32d360cb in the triage console for the audit trail.

Comment thread .ci/jenkins/lib/build-wheel-matrix.yaml Outdated
@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-dl-gpu-ep · commit f7f45454

TL;DR: The build and Docker image compilation all succeeded; the job failed in the "Allocate DL EP Environment" stage because the SLURM salloc for a GB200 node on partition gb200nvl72_cx8 never got resources and hit its 1-hour --immediate=3600 cap, exiting with salloc: error: Unable to allocate resources: Connection timed out. This is a cluster capacity/infra issue, not a code defect — retry the job (or increase allocation patience / free cluster capacity), do not change PR code.

Full analysis

Summary: Jenkins stage "Allocate DL EP Environment" (node 183/200) failed after ~60 min when SLURM could not allocate a GB200 test node.

Root cause: salloc -N 1 -p gb200nvl72_cx8 --immediate=3600 --time=01:30:00 ... --account=blackwell queued the job (Pending job allocation 1668174, "queued and waiting for resources") but the cluster never freed a node within the 3600s immediate window, ending with salloc: error: Unable to allocate resources: Connection timed out (script exit code 1). This is a scheduler/capacity/connectivity problem on dlcluster.nvidia.com, not a hang in application code — the log shows the allocation waiting on the external SLURM scheduler the entire time, and there is also a mid-stage Jenkins agent channel drop (ChannelClosedException at 08:24:31) indicating an infra/connectivity disruption. The upstream compile steps (168/150) and UCX/NIXL builds completed successfully.

Implicated commit: none — not caused by commit [REDACTED:Hex High Entropy String] or PR #1948; infrastructure failure.

File: n/a (Jenkins pipeline SLURM allocation step, slurm.allocation in the swx-jenkins-lib shared library; job id file /mnt/pvc/nixl-ci-dl-gpu-ep/job_id_ep_master_483.txt)

Suggested fix: Re-run the build — this is a transient GB200 cluster-capacity/connectivity failure. If it recurs, (1) check gb200nvl72_cx8 partition availability and the blackwell account's queue on dlcluster.nvidia.com, (2) consider raising --immediate/adding retry-with-backoff around the salloc in the allocation stage so a busy cluster queues rather than hard-failing, and (3) investigate the Jenkins agent ChannelClosedException at 08:24:31 as a possible correlated infra disruption. Do not raise the build time limit — the build was fast; the wait was external scheduler queueing.

Related: none

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 6b96b89b-41e6-4ac7-90f7-d32a3f8f764c in the triage console for the audit trail.

The vLLM/SGLang sanity stages fetch Qwen/Qwen3-8B at runtime from
huggingface.co, which rate-limits the shared CI egress IP (429), failing
the prefetch before the servers even start.

Route the prefetch through the internal urm HuggingFace mirror instead:
SANITY_HF_ENDPOINT is passed into the SLURM container as HF_ENDPOINT,
where huggingface_hub picks it up. The mirror allows anonymous reads, so
no token is involved. Long HF_HUB_*_TIMEOUT values absorb the mirror's
cold-cache first-fetch latency.

Signed-off-by: NirWolfer <nwolfer@nvidia.com>
@NirWolfer
NirWolfer force-pushed the ci/hf-token-rate-limit-fix branch from c38742e to 90a98e4 Compare July 27, 2026 12:56
@NirWolfer

Copy link
Copy Markdown
Contributor Author

/build

@NirWolfer
NirWolfer requested a review from dpressle July 27, 2026 12:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.gitlab/test_vllm_sglang_sanity.sh (1)

105-106: ⚠️ Potential issue | 🟠 Major

Bound Hugging Face timeouts to the CI budget.

The 86,400-second defaults can outlive the 40-minute Jenkins sanity timeout, so a stalled request may hold the job and allocated resources until the outer timeout kills it. This repeats the previously reported timeout-budget issue; preserve explicit overrides but use a bounded default such as 900–1800 seconds.

Proposed fix
-export HF_HUB_ETAG_TIMEOUT="${HF_HUB_ETAG_TIMEOUT:-86400}"
-export HF_HUB_DOWNLOAD_TIMEOUT="${HF_HUB_DOWNLOAD_TIMEOUT:-86400}"
+export HF_HUB_ETAG_TIMEOUT="${HF_HUB_ETAG_TIMEOUT:-1800}"
+export HF_HUB_DOWNLOAD_TIMEOUT="${HF_HUB_DOWNLOAD_TIMEOUT:-1800}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.gitlab/test_vllm_sglang_sanity.sh around lines 105 - 106, Reduce the
default values for HF_HUB_ETAG_TIMEOUT and HF_HUB_DOWNLOAD_TIMEOUT in the sanity
script to a bounded 900–1800 second range so requests remain within the CI
budget, while preserving explicit environment variable overrides.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.gitlab/test_vllm_sglang_sanity.sh:
- Around line 105-106: Reduce the default values for HF_HUB_ETAG_TIMEOUT and
HF_HUB_DOWNLOAD_TIMEOUT in the sanity script to a bounded 900–1800 second range
so requests remain within the CI budget, while preserving explicit environment
variable overrides.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: da4872f4-d746-4bb8-90ad-b884e0048f46

📥 Commits

Reviewing files that changed from the base of the PR and between c38742e and 90a98e4.

📒 Files selected for processing (3)
  • .ci/docs/ci-overview.md
  • .ci/jenkins/lib/build-wheel-matrix.yaml
  • .gitlab/test_vllm_sglang_sanity.sh

@NirWolfer

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-gpu · commit 66609d94

TL;DR: The "Run Nixlbench tests" stage crashed with a SIGSEGV (exit code 139) inside the UCCL backend during engine teardown of the UCCL / READ / DRAM→DRAM benchmark; this is a UCCL plugin bug, not caused by the triggering PR #1948 (a CI-only HuggingFace-auth change).

Full analysis

Summary: Jenkins nixl-ci-gpu #2950 failed in the "Run Nixlbench tests" stage (node 375) when a nixlbench --backend UCCL --op_type READ --initiator_seg_type DRAM --target_seg_type DRAM worker segfaulted (srun: task 0: Exited with exit code 139), and separately the build_helper/ucx-master stage (node 124) failed but was superseded by a retry (node 160 SUCCESS).

Root cause: A segmentation fault in the UCCL backend. The benchmark itself completed — the log shows the final result line printed (16384 4 1.656560 …) followed by Destroying Engine... / Stop background accept... / Engine destroyed, then parallel: This job failed and exit 139. So the crash occurred during UCCL engine/connection destruction (the background-accept thread / epoll_client teardown after "Stop background accept..."), i.e. a shutdown-time use-after-free or race in the UCCL plugin — not a wall-clock timeout and not related to PR #1948. The pin_thread_to_numa … Failed to set thread affinity to NUMA node 1 and NIC filtered as unusable: mlx5_4 messages are pre-existing benign warnings present in every iteration, not the cause. This config runs late in the matrix, consistent with an intermittent teardown race.

Implicated commit: unknown for the exact regression; the UCCL backend is owned by Pravein Govindan Kannan and the most recent substantive UCCL changes are f8e2221f "Enable local xfer for UCCL backend (#1428)" and 63c494e1 "UCCL: Simplify and Optimize for batch transfers (#1271)". The triggering commit 66609d9 / PR #1948 is CI-only and is NOT the cause.

File: src/plugins/uccl/uccl_backend.cpp (UCCL engine/connection destruction path; teardown after "Stop background accept…", interacting with the UCCL rdma/epoll_client.h event loop).

Suggested fix: Reproduce locally with the exact failing config (--backend UCCL --op_type READ --initiator_seg_type DRAM --target_seg_type DRAM --check_consistency via ETCD runtime) under a core dump / ASan / gdb (see docs/DebugCoreDumps.md referenced at the end of the log) to get the crashing frame, and audit the UCCL engine-destroy sequence for a shutdown race/use-after-free (background accept thread accessing connection state after Destroying Engine). Since this is unrelated to PR #1948, re-run the job to confirm intermittency and open a UCCL-backend bug tagged to its maintainer; do not block PR #1948 on it.

Related: PR #1948 (triggering, CI-only, unrelated); UCCL backend PRs #1428, #1271, #895.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agentnixl-ci-dl-gpu-ep · commit 66609d94

TL;DR: The nixl build compiled and the Docker image pushed successfully; the job failed in the "Allocate DL EP Environment" stage because salloc on the gb200nvl72_cx8 Slurm partition sat queued for the full --immediate=3600 (1 h) window with no free GB200 nodes and returned Unable to allocate resources. This is a cluster capacity/infra issue, not a code regression — retry when GB200 nodes are available (or raise/re-tune the immediate-allocation timeout & queueing behavior).

Full analysis

Summary: Stage "Allocate DL EP Environment" (node 183/200) failed with salloc: error: Unable to allocate resources: Connection timed out after the compile and Docker-push stages succeeded.

Root cause: GPU resource allocation on the Slurm cluster timed out. The log shows a single blocking salloc command issued at 14:25:31 with --immediate=3600; Slurm accepted the request (Pending job allocation 1670858 / job queued and waiting for resources) but no node in the gb200nvl72_cx8 partition became free within the 3600 s immediate window, so at 15:25:39 — exactly ~60 min later — salloc exited with Unable to allocate resources: Connection timed out (exit code 1). The gap here is not a hung nixl process; it is salloc legitimately waiting in the scheduler queue for GB200 capacity that never freed up. The build_helper_dl_ep matrix "failures" (nodes 124/125) are the expected parallel "pipeline stop" behavior and were retried successfully (nodes 150/142); they are not the cause.

Implicated commit: unknown — not caused by commit 66609d9; the failure is in CI infrastructure/cluster scheduling, not the built code (build + install + image push all succeeded).

File: N/A (CI pipeline Slurm allocation step: slurm.allocation via swx-jenkins-lib; salloc ... -p gb200nvl72_cx8 --immediate=3600 --time=01:30:00).

Suggested fix: Retrigger the build once GB200 nodes on the gb200nvl72_cx8 partition are available — this is a transient capacity/queue timeout. If it recurs, work with the cluster/infra team to (a) confirm GB200 partition health and quota for --account=blackwell, and (b) reconsider the allocation strategy: the current --immediate=3600 blocks a full hour and still fails; consider a shorter immediate timeout with automatic Jenkins retry/backoff, or drop --immediate and allow proper queued allocation with a bounded stage timeout, so a busy cluster produces a fast, clearly-labeled "no capacity" result instead of a 60-minute stall. Do not treat this as a wall-clock limit to raise on a running test — nothing was hung; salloc was correctly waiting for unavailable hardware.

Related: none

@NirWolfer
NirWolfer merged commit fca3d58 into ai-dynamo:main Jul 27, 2026
25 of 29 checks passed
@NirWolfer
NirWolfer deleted the ci/hf-token-rate-limit-fix branch July 27, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants