Skip to content

fix(ci): resolve flashinfer-jit-cache index to the nearest published CUDA tag - #2086

Merged
slin1237 merged 1 commit into
mainfrom
fix/flashinfer-jit-cache-post-release
Aug 11, 2026
Merged

slin1237 merged 1 commit into
mainfrom
fix/flashinfer-jit-cache-post-release

Conversation

@slin1237

@slin1237 slin1237 commented Aug 10, 2026 •

Copy link
Copy Markdown
Member

Problem

Every vLLM e2e lane dies in Setup (~1m40s) on main and on this PR's first revision:

× No solution found ... flashinfer-jit-cache==0.6.16.post3 was not found in the package registry

Real cause (first revision of this PR diagnosed it wrong)

torch now resolves to 2.13.0+cu132 in the vLLM install. The scripts derive the flashinfer wheel index from torch.version.cuda, but flashinfer hosts one index per CUDA tag and its newest is cu130 — https://flashinfer.ai/whl/cu132 404s, and uv reports a missing index as "package not found in the registry". The .post3 in the error was a red herring: 0.6.16.post3 exists on the cu130 index (verified live). This PR's first revision added a version fallback for that red herring; both its installs failed identically because the index itself was absent.

Fix

CUDA minor versions are ABI-compatible, so probe the index URL and walk down to the nearest published tag within the same major:

CUDA_MAJOR_FLOOR=$((CUDA_TAG / 10 * 10))
while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ] \
    && ! curl -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
    CUDA_TAG=$((CUDA_TAG - 1))
done

Applied to both ci_install_vllm.sh and ci_install_sglang.sh — sglang's torch is still cu130 so its lanes pass today, but it carries the same latent assumption. The major floor stops the walk from crossing into cu12x (a different ABI).

Verified against the live index: 132 → 130; 130 stays 130.

Verification

The vLLM lanes on this PR exercise the cu132→cu130 walk end-to-end; the sglang lanes prove no regression on the already-working path.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved FlashInfer installation reliability by automatically selecting the nearest available CUDA wheel index within the same CUDA major version.
    • Added fallback handling for unsupported CUDA minor versions, helping installations use a compatible JIT cache when an exact match is unavailable.
    • Ensured installation attempts consistently use the appropriate CUDA-specific package index.

Walkthrough

The SGLang and vLLM CI installation scripts now find the nearest published FlashInfer CUDA wheel index within the same CUDA major version before installing the JIT cache.

Changes

FlashInfer CUDA index fallback

Layer / File(s) Summary
Resolve published CUDA wheel indexes
scripts/ci_install_sglang.sh, scripts/ci_install_vllm.sh
Both scripts decrement the CUDA minor tag until they find an available FlashInfer wheel index. The search does not cross the CUDA major-version floor.

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

Possibly related PRs

  • smg-project/smg#333: Both changes update FlashInfer CUDA wheel index selection in the SGLang installation script.
  • smg-project/smg#1662: Both changes update FlashInfer installation logic that selects CUDA-compatible wheel indexes.

Suggested labels: ci

Suggested reviewers: catherinesue, key4ng

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly summarizes the main change: resolving FlashInfer JIT-cache indexes to the nearest published CUDA tag.
Description check ✅ Passed The description explains the FlashInfer CUDA index failure, the fallback fix, affected scripts, and verification steps.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/flashinfer-jit-cache-post-release

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@claude

claude Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

👋 The PR description doesn't fully follow
PULL_REQUEST_TEMPLATE.md:

  • Missing header: ## Description
  • Missing header: ### Problem
  • Missing header: ### Solution
  • Missing header: ## Changes
  • Missing header: ## Test Plan

Please update the PR description so reviewers have the context they need.

@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.

Clean fix. The || fallback with ${V%.post*} parameter expansion is correct — idempotent on non-post versions, and set -euo pipefail ensures both scripts still fail loudly if neither version exists. Both scripts are updated consistently. LGTM.

@coderabbitai coderabbitai 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.

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 `@scripts/ci_install_sglang.sh`:
- Around line 56-62: Both installers currently run the fallback after any failed
uv pip install, masking transient and other errors. Update the installation
logic in scripts/ci_install_sglang.sh lines 56-62 and scripts/ci_install_vllm.sh
lines 90-96 to use one validated policy: only try the base version for
FLASHINFER_VERSION values matching .postN and confirmed missing distributions;
propagate network, authentication, metadata, non-post, and release-candidate
failures without retrying the same specification.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d781487d-23a9-46d1-a0fa-4f0c36170f0e

📥 Commits

Reviewing files that changed from the base of the PR and between a600833 and e710920.

📒 Files selected for processing (2)
  • scripts/ci_install_sglang.sh
  • scripts/ci_install_vllm.sh

Comment thread scripts/ci_install_sglang.sh Outdated
…CUDA tag

Every vLLM e2e lane dies in setup since torch resolved to 2.13.0+cu132:
the install scripts derive the flashinfer wheel index from
torch.version.cuda, but flashinfer hosts one index per CUDA tag and its
newest is cu130 - https://flashinfer.ai/whl/cu132 404s, and uv reports
a missing index as "flashinfer-jit-cache was not found in the package
registry" (first hit: main run 31430981291 at a600833; the .post3 in
that message was a red herring - 0.6.16.post3 exists on cu130).

CUDA minor versions are ABI-compatible, so probe the index URL and walk
down to the nearest published tag within the same major (cu132 -> cu130
today; a same-major floor stops the walk from crossing into cu12x).
Applied to both ci_install_vllm.sh and ci_install_sglang.sh - sglang's
torch is still cu130 so its lanes pass today, but it carries the same
latent assumption.

Verified against the live index: the walk resolves 132 -> 130 and
leaves 130 untouched.

Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>
@slin1237
slin1237 force-pushed the fix/flashinfer-jit-cache-post-release branch from e710920 to cfe9468 Compare August 10, 2026 23:00
@slin1237 slin1237 changed the title fix(ci): tolerate flashinfer post-releases without a jit-cache wheel fix(ci): resolve flashinfer-jit-cache index to the nearest published CUDA tag Aug 10, 2026
Comment on lines +95 to +98
while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ] \
&& ! curl -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
CUDA_TAG=$((CUDA_TAG - 1))
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Nit: The curl probes have no timeout. If flashinfer.ai is unresponsive (not down — just slow), each loop iteration blocks on curl's default unlimited timeout, and the walk could stall CI until the job-level timeout kills it. Consider adding --connect-timeout 5 --max-time 10 to bound each probe. Same applies to the identical loop in scripts/ci_install_sglang.sh:61-64.

Suggested change
while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ] \
&& ! curl -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
CUDA_TAG=$((CUDA_TAG - 1))
done
CUDA_MAJOR_FLOOR=$((CUDA_TAG / 10 * 10))
while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ] \
&& ! curl -sfo /dev/null --connect-timeout 5 --max-time 10 "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
CUDA_TAG=$((CUDA_TAG - 1))

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 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 `@scripts/ci_install_sglang.sh`:
- Around line 61-65: Update the CUDA index-selection loops in
scripts/ci_install_sglang.sh lines 61-65 and scripts/ci_install_vllm.sh lines
94-98 to validate that each candidate index contains a compatible
flashinfer-jit-cache==${FLASHINFER_VERSION} wheel for the runner platform,
rather than accepting any successful HTTP response. Preserve the fallback
decrement behavior, and fail explicitly when no compatible CUDA index is found.
- Around line 61-64: Update the FlashInfer probe loops in
scripts/ci_install_sglang.sh lines 61-64 and scripts/ci_install_vllm.sh lines
95-98 so both use connection and total-operation timeouts and capture HTTP
status separately from curl transport errors. Decrement the CUDA tag only when
the probe returns HTTP 404, exit immediately for other HTTP statuses or
transport failures, and ensure the CUDA_MAJOR_FLOOR validation still runs after
all eligible tags are exhausted.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 07710358-e3be-4081-9779-93e8b952ef08

📥 Commits

Reviewing files that changed from the base of the PR and between e710920 and cfe9468.

📒 Files selected for processing (2)
  • scripts/ci_install_sglang.sh
  • scripts/ci_install_vllm.sh

Comment on lines +61 to +64
while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ] \
&& ! curl -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
CUDA_TAG=$((CUDA_TAG - 1))
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target files and line ranges ---'
for f in scripts/ci_install_sglang.sh scripts/ci_install_vllm.sh; do
  printf '\n### %s\n' "$f"
  wc -l "$f"
  sed -n '35,115p' "$f"
done

printf '%s\n' '--- curl and timeout usage in target scripts ---'
rg -n -C 2 'curl|timeout|CURL|set -|CUDA_TAG|CUDA_MAJOR_FLOOR' \
  scripts/ci_install_sglang.sh scripts/ci_install_vllm.sh

printf '%s\n' '--- references and likely tests ---'
rg -n -C 2 'ci_install_sglang|ci_install_vllm|flashinfer-jit-cache|CUDA_MAJOR_FLOOR|CUDA_TAG' \
  . --glob '!node_modules' --glob '!dist' --glob '!build' || true

Repository: smg-project/smg

Length of output: 16635


🌐 Web query:

curl man page --fail HTTP 400 errors --connect-timeout --max-time default timeout behavior

💡 Result:

The curl command-line utility behaves as follows regarding the requested options and behaviors: --fail (-f): When this option is used, curl will exit with error code 22 if an HTTP server returns an error response code of 400 or greater [1][2]. By default, curl does not consider HTTP response codes to indicate failure and will output the server's response body regardless of the status code [1][3]. If you wish to see the error response body while still triggering an error exit, use --fail-with-body instead [4][1]. --connect-timeout: This option limits the time allowed for the connection phase (including DNS resolution and TCP/TLS/QUIC handshakes) [5][6]. If the connection is not established within the specified time, curl exits with error code 28 [5]. If this option is not set, curl relies on the default built-in timeout, which is typically 300 seconds (5 minutes) [7][6]. --max-time (-m): This option sets the maximum time, in seconds, allowed for the entire operation [8][9]. If this time is exceeded, curl exits with error code 28 [8]. By default, curl has no maximum time limit for an operation and will wait indefinitely for a server response unless a connection timeout is triggered or the server closes the connection [8][10]. In summary, if no timeout options are explicitly provided, curl generally waits indefinitely for data once a connection is established, though individual operations may still be subject to system-level or network-level limits [8][10].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
from pathlib import Path

files = [
    Path("scripts/ci_install_sglang.sh"),
    Path("scripts/ci_install_vllm.sh"),
]

for path in files:
    text = path.read_text()
    marker = 'while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ]'
    start = text.index(marker)
    end = text.index("\n    done" if path.name == "ci_install_sglang.sh" else "\n    done", start)
    loop = text[start:end + len("\n    done")]
    print(f"{path}:")
    print(loop)
    print()

def selected_tag(initial, probe_results):
    floor = initial // 10 * 10
    tag = initial
    i = 0
    while tag > floor and not probe_results[i]:
        tag -= 1
        i += 1
    return tag, i

cases = {
    "404 then 200": [False, True],
    "500 then 200": [False, True],
    "transport failure then 200": [False, True],
    "all failures": [False, False],
    "initial 130 (floor, no probe)": [],
}

for name, results in cases.items():
    initial = 132 if name != "initial 130 (floor, no probe)" else 130
    print(name, "=>", selected_tag(initial, results))
PY

Repository: smg-project/smg

Length of output: 487


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
from pathlib import Path

files = [
    Path("scripts/ci_install_sglang.sh"),
    Path("scripts/ci_install_vllm.sh"),
]

for path in files:
    text = path.read_text()
    marker = 'while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ]'
    start = text.index(marker)
    end = text.index("\n    done", start)
    print(f"{path}:")
    print(text[start:end + len("\n    done")])
    print()

def selected_tag(initial, probe_results):
    floor = initial // 10 * 10
    tag = initial
    i = 0
    while tag > floor and not probe_results[i]:
        tag -= 1
        i += 1
    return tag, i

cases = {
    "404 then 200": [False, True],
    "500 then 200": [False, True],
    "transport failure then 200": [False, True],
    "all failures": [False, False],
    "initial 130 (floor, no probe)": [],
}

for name, results in cases.items():
    initial = 132 if name != "initial 130 (floor, no probe)" else 130
    print(name, "=>", selected_tag(initial, results))
PY

Repository: smg-project/smg

Length of output: 487


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
from pathlib import Path

for path in (Path("scripts/ci_install_sglang.sh"), Path("scripts/ci_install_vllm.sh")):
    lines = path.read_text().splitlines()
    start = next(i for i, line in enumerate(lines)
                 if line.lstrip().startswith('while [ "${CUDA_TAG}"'))
    end = next(i for i in range(start, len(lines)) if lines[i].strip() == "done")
    print(f"{path}:{start + 1}-{end + 1}")
    print("\n".join(lines[start:end + 1]))
    print()

def selected_tag(initial, probe_results):
    floor = initial // 10 * 10
    tag = initial
    i = 0
    while tag > floor and not probe_results[i]:
        tag -= 1
        i += 1
    return tag, i

for name, initial, results in (
    ("404 then 200", 132, [False, True]),
    ("500 then 200", 132, [False, True]),
    ("transport failure then 200", 132, [False, True]),
    ("all failures", 132, [False, False]),
    ("initial floor", 130, []),
):
    print(f"{name}: selected cu{selected_tag(initial, results)[0]}, probes={selected_tag(initial, results)[1]}")
PY

Repository: smg-project/smg

Length of output: 819


🏁 Script executed:

#!/bin/bash
set -u

for tag in 132 131 130; do
  url="https://flashinfer.ai/whl/cu${tag}/flashinfer-jit-cache/"
  result=$(curl -sS -o /dev/null --connect-timeout 5 --max-time 15 \
    -w 'http=%{http_code} exit=%{exitcode}' "$url" 2>&1) || true
  printf 'cu%s: %s\n' "$tag" "$result"
done

Repository: smg-project/smg

Length of output: 222


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
from pathlib import Path

for path in (Path("scripts/ci_install_sglang.sh"), Path("scripts/ci_install_vllm.sh")):
    lines = path.read_text().splitlines()
    start = next(i for i, line in enumerate(lines)
                 if line.lstrip().startswith('while [ "${CUDA_TAG}"'))
    end = next(i for i in range(start, len(lines)) if lines[i].strip() == "done")
    print(f"{path}:{start + 1}-{end + 1}")
    print("\n".join(lines[start:end + 1]))
    print()

def selected_tag(initial, probe_results):
    floor = initial // 10 * 10
    tag = initial
    i = 0
    while tag > floor and not probe_results[i]:
        tag -= 1
        i += 1
    return tag, i

for name, initial, results in (
    ("404 then 200", 132, [False, True]),
    ("500 then 200", 132, [False, True]),
    ("transport failure then 200", 132, [False, True]),
    ("all failures", 132, [False, False]),
    ("initial floor", 130, []),
):
    tag, probes = selected_tag(initial, results)
    print(f"{name}: selected cu{tag}, probes={probes}")
PY

Repository: smg-project/smg

Length of output: 819


🔴 Important: Make both FlashInfer index probes status-aware and bounded.

curl -sfo returns nonzero for 404, 5xx, and transport failures. The ! condition treats each result as a missing index, so transient failures can select an unintended lower CUDA tag. The loop also skips CUDA_MAJOR_FLOOR validation after all probes fail. Add connection and total-operation timeouts. Decrement only for HTTP 404. Exit on other HTTP or transport failures in scripts/ci_install_sglang.sh and scripts/ci_install_vllm.sh.

📍 Affects 2 files
  • scripts/ci_install_sglang.sh#L61-L64 (this comment)
  • scripts/ci_install_vllm.sh#L95-L98
🤖 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 `@scripts/ci_install_sglang.sh` around lines 61 - 64, Update the FlashInfer
probe loops in scripts/ci_install_sglang.sh lines 61-64 and
scripts/ci_install_vllm.sh lines 95-98 so both use connection and
total-operation timeouts and capture HTTP status separately from curl transport
errors. Decrement the CUDA tag only when the probe returns HTTP 404, exit
immediately for other HTTP statuses or transport failures, and ensure the
CUDA_MAJOR_FLOOR validation still runs after all eligible tags are exhausted.

Source: Coding guidelines

Comment on lines +61 to +65
while [ "${CUDA_TAG}" -gt "${CUDA_MAJOR_FLOOR}" ] \
&& ! curl -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
CUDA_TAG=$((CUDA_TAG - 1))
done
CU_VERSION="cu${CUDA_TAG}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- target files ---'
for f in scripts/ci_install_sglang.sh scripts/ci_install_vllm.sh scripts/update_whl_index.py; do
  if [ -f "$f" ]; then
    printf '\n### %s (%s lines)\n' "$f" "$(wc -l < "$f")"
    case "$f" in
      scripts/update_whl_index.py) sed -n '1,240p' "$f" ;;
      *) sed -n '1,150p' "$f" ;;
    esac
  else
    printf 'MISSING: %s\n' "$f"
  fi
done

printf '\n--- relevant references ---\n'
rg -n -C 3 'CUDA_TAG|CU_VERSION|flashinfer|update_whl_index|curl' scripts .github tests 2>/dev/null | head -400 || true

Repository: smg-project/smg

Length of output: 44448


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- changed files ---'
git diff --name-only 2>/dev/null || true
git status --short 2>/dev/null || true

printf '\n--- test and CI references ---\n'
rg -n -C 3 'ci_install_sglang|ci_install_vllm|CUDA_MAJOR_FLOOR|flashinfer-jit-cache|flashinfer' \
  -g '*test*' -g '*.yml' -g '*.yaml' -g '*.sh' -g '*.py' . 2>/dev/null | head -400 || true

Repository: smg-project/smg

Length of output: 9204


🏁 Script executed:

#!/bin/bash
set -u

python3 - <<'PY'
from pathlib import Path
for name in ("scripts/ci_install_sglang.sh", "scripts/ci_install_vllm.sh"):
    text = Path(name).read_text()
    print(f"{name}:")
    for line in text.splitlines():
        if "curl -sfo /dev/null" in line or "uv pip install \"flashinfer-jit-cache" in line:
            print("  " + line.strip())
PY

printf '\n--- live FlashInfer index probes ---\n'
for tag in cu129 cu130 cu131 cu132; do
    url="https://flashinfer.ai/whl/${tag}/flashinfer-jit-cache/"
    body="$(mktemp)"
    code="$(curl -L --connect-timeout 10 --max-time 30 -sS -o "$body" -w '%{http_code}' "$url" 2>/tmp/flashinfer-curl.err || true)"
    printf '%s status=%s bytes=%s\n' "$tag" "$code" "$(wc -c < "$body")"
    if [ "$code" = 200 ]; then
        grep -Eio 'href="[^"]+flashinfer[^"]+\.whl[^"]*"' "$body" | head -10 || true
        grep -Eio 'flashinfer-jit-cache[^"< ]*' "$body" | head -10 || true
    fi
    rm -f "$body"
done
if [ -s /tmp/flashinfer-curl.err ]; then
    printf '\n--- curl diagnostics ---\n'
    cat /tmp/flashinfer-curl.err
fi

Repository: smg-project/smg

Length of output: 5165


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
import re
from pathlib import Path

def extract(path):
    s = Path(path).read_text()
    probe = re.search(r'while \[ "\$\{CUDA_TAG\}" > "\$\{CUDA_MAJOR_FLOOR\}" \].*?done', s, re.S)
    print(f"\n{path}\n{probe.group(0) if probe else 'loop not found'}")

extract("scripts/ci_install_sglang.sh")
extract("scripts/ci_install_vllm.sh")
PY

printf '\n--- deterministic loop behavior with mocked curl ---\n'
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

cat >"$tmp/mock-curl" <<'SH'
#!/bin/sh
# Return success while writing an empty response, which models an empty 200 page.
exit 0
SH
chmod +x "$tmp/mock-curl"

for start in 132 131; do
    CUDA_TAG="$start"
    CUDA_MAJOR_FLOOR=$((CUDA_TAG / 10 * 10))
    iterations=0
    while [ "$CUDA_TAG" -gt "$CUDA_MAJOR_FLOOR" ] \
        && ! "$tmp/mock-curl" -sfo /dev/null "https://example.invalid/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
        CUDA_TAG=$((CUDA_TAG - 1))
        iterations=$((iterations + 1))
    done
    printf 'start=%s => selected=cu%s iterations=%s\n' "$start" "$CUDA_TAG" "$iterations"
done

printf '\n--- empty-index behavior in update_whl_index.py ---\n'
tmprepo="$(mktemp -d)"
tmpwheels="$(mktemp -d)"
python3 scripts/update_whl_index.py \
  --package flashinfer-jit-cache --cuda 130 --release-tag test-release \
  --wheel-dir "$tmpwheels" --whl-repo-dir "$tmprepo"
find "$tmprepo" -type f -print -exec sh -c 'printf " bytes="; wc -c < "$1"; cat "$1"' sh {} \;

Repository: smg-project/smg

Length of output: 691


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- versions and wheel tags in live package indexes ---'
for tag in cu129 cu130; do
    body="$(mktemp)"
    code="$(curl -L --connect-timeout 10 --max-time 30 -sS -o "$body" -w '%{http_code}' \
        "https://flashinfer.ai/whl/${tag}/flashinfer-jit-cache/" 2>/tmp/flashinfer-curl.err || true)"
    printf '\n%s status=%s bytes=%s\n' "$tag" "$code" "$(wc -c < "$body")"
    if [ "$code" = 200 ]; then
        python3 - "$body" <<'PY'
import re, sys
from collections import defaultdict

text = open(sys.argv[1], encoding="utf-8").read()
links = re.findall(r'href="([^"]+flashinfer_jit_cache-[^"]+\.whl)(?:#[^"]*)?"', text)
by_version = defaultdict(list)
for link in links:
    name = link.rsplit("/", 1)[-1].split("#", 1)[0]
    # filename: flashinfer_jit_cache-VERSION+CUDA-python-abi-platform.whl
    m = re.match(r"flashinfer_jit_cache-([^+]+)\+[^-]+-(cp[^-]+)-([^-]+)-(.+)\.whl$", name)
    if m:
        version, py, abi, platform = m.groups()
        by_version[version].append((py, abi, platform))
    else:
        print("UNPARSED", name)
for version in sorted(by_version):
    print(version, sorted(set(by_version[version])))
PY
    fi
    rm -f "$body"
done

printf '\n--- source evidence for empty package pages ---\n'
nl -ba scripts/update_whl_index.py | sed -n '45,85p'

printf '\n--- shell-only reproduction of the probe invariant ---\n'
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
cat >"$tmp/curl" <<'SH'
#!/bin/sh
# Simulate curl -sfo against an empty HTTP 200 page.
: > "$3"
exit 0
SH
chmod +x "$tmp/curl"

for start in 132 131; do
    CUDA_TAG="$start"
    CUDA_MAJOR_FLOOR=$((CUDA_TAG / 10 * 10))
    calls=0
    while [ "$CUDA_TAG" -gt "$CUDA_MAJOR_FLOOR" ] \
        && ! "$tmp/curl" -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
        CUDA_TAG=$((CUDA_TAG - 1))
        calls=$((calls + 1))
    done
    printf 'empty-200 start=cu%s selected=cu%s fallback_steps=%s\n' \
        "$start" "$CUDA_TAG" "$calls"
done

printf '\n--- probe failure at every minor index ---\n'
cat >"$tmp/curl" <<'SH'
#!/bin/sh
exit 6
SH
chmod +x "$tmp/curl"

for start in 132 131; do
    CUDA_TAG="$start"
    CUDA_MAJOR_FLOOR=$((CUDA_TAG / 10 * 10))
    calls=0
    while [ "$CUDA_TAG" -gt "$CUDA_MAJOR_FLOOR" ] \
        && ! "$tmp/curl" -sfo /dev/null "https://flashinfer.ai/whl/cu${CUDA_TAG}/flashinfer-jit-cache/"; do
        CUDA_TAG=$((CUDA_TAG - 1))
        calls=$((calls + 1))
    done
    printf 'all-fail start=cu%s selected=cu%s fallback_steps=%s\n' \
        "$start" "$CUDA_TAG" "$calls"
done

Repository: smg-project/smg

Length of output: 11680


Validate the requested FlashInfer wheel before selecting a CUDA index.

Both loops accept any successful package-index response. A 200 response can contain no wheel, or no wheel for ${FLASHINFER_VERSION} and the runner platform. Select an index only when it contains a compatible flashinfer-jit-cache==${FLASHINFER_VERSION} wheel. Fail explicitly when no compatible index exists.

Apply this to scripts/ci_install_sglang.sh#L61-L65 and scripts/ci_install_vllm.sh#L94-L98.

📍 Affects 2 files
  • scripts/ci_install_sglang.sh#L61-L65 (this comment)
  • scripts/ci_install_vllm.sh#L94-L98
🤖 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 `@scripts/ci_install_sglang.sh` around lines 61 - 65, Update the CUDA
index-selection loops in scripts/ci_install_sglang.sh lines 61-65 and
scripts/ci_install_vllm.sh lines 94-98 to validate that each candidate index
contains a compatible flashinfer-jit-cache==${FLASHINFER_VERSION} wheel for the
runner platform, rather than accepting any successful HTTP response. Preserve
the fallback decrement behavior, and fail explicitly when no compatible CUDA
index is found.

Source: Coding guidelines

@slin1237
slin1237 merged commit be1ca5d into main Aug 11, 2026
50 of 51 checks passed
@slin1237
slin1237 deleted the fix/flashinfer-jit-cache-post-release branch August 11, 2026 00:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant