Skip to content

fix: let FLASHINFER_CUBIN_DIR env var override flashinfer-cubin package path#3062

Open
ianliuy wants to merge 1 commit intoflashinfer-ai:mainfrom
ianliuy:fix/issue-2976
Open

fix: let FLASHINFER_CUBIN_DIR env var override flashinfer-cubin package path#3062
ianliuy wants to merge 1 commit intoflashinfer-ai:mainfrom
ianliuy:fix/issue-2976

Conversation

@ianliuy
Copy link
Copy Markdown

@ianliuy ianliuy commented Apr 14, 2026

What's broken?

When flashinfer-cubin is installed (all pre-built container images), setting FLASHINFER_CUBIN_DIR to redirect cubin storage to a writable directory is silently ignored. Non-root containers crash with PermissionError on startup.

Who is affected?

All non-root K8s/OpenShift deployments using pre-built images with flashinfer-cubin (e.g., vLLM containers). No workaround exists.

Why does it happen?

_get_cubin_dir() checks the flashinfer-cubin package before the env var. When the package is installed, the env var is never reached. Introduced in PR #1718 (intentional priority, but didn't consider non-root containers).

Every other env var in env.py follows "env var overrides automatic discovery." This was the sole exception.

How did we fix it?

Swap priority: env var -> package -> default cache. Pure code-block reorder (~8 lines moved + docstring/comments updated). Zero new logic.

Before:

def _get_cubin_dir():
    if has_flashinfer_cubin():          # always wins
        return package_path
    env_dir = os.getenv("FLASHINFER_CUBIN_DIR")  # unreachable
    ...

After:

def _get_cubin_dir():
    env_dir = os.getenv("FLASHINFER_CUBIN_DIR")  # user override first
    if env_dir:
        return pathlib.Path(env_dir)
    if has_flashinfer_cubin():          # package fallback
        return package_path
    ...

Default behavior (no env var set) is unchanged.

Note: If you previously had a stale FLASHINFER_CUBIN_DIR that was silently ignored, it will now take effect. Unset it if unneeded.

How do we know it works?

Added tests/test_env.py with 4 regression tests covering the full priority matrix:

  • env var + package -> env var wins (the bug)
  • package only -> package wins
  • env var only -> env var wins
  • neither -> default cache dir

All 4 pass. Pre-commit hooks (ruff, mypy, format) all pass.

Fixes #2976
Related: #2834

@aleozlx @yzh119

Summary by CodeRabbit

  • Bug Fixes

    • Improved CUBIN directory lookup to prioritize environment variable configuration when set, allowing users greater control over directory selection.
  • Tests

    • Added regression tests for CUBIN directory selection behavior across various configuration scenarios.

…ge path

_get_cubin_dir() checked the flashinfer-cubin package before the
FLASHINFER_CUBIN_DIR environment variable, making the env var silently
ignored when the package was installed. This broke all non-root
Kubernetes/OpenShift deployments where users need to redirect cubin
storage to a writable directory.

Swap the priority order so the env var is checked first, matching the
standard Unix convention that explicit user overrides take precedence
over automatic discovery. Default behavior (no env var set) is
unchanged.

Add regression tests for the priority logic in _get_cubin_dir().

Fixes flashinfer-ai#2976
Related: flashinfer-ai#2834
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

The pull request reorders the priority logic in _get_cubin_dir() so the FLASHINFER_CUBIN_DIR environment variable is checked first before the installed flashinfer_cubin package, allowing users to override cubin directory location in restricted environments. Comprehensive regression tests validate the new priority behavior across all scenarios.

Changes

Cohort / File(s) Summary
Priority Reordering
flashinfer/jit/env.py
Restructured _get_cubin_dir() to check FLASHINFER_CUBIN_DIR environment variable first and return immediately if set, moving the flashinfer_cubin package check to second priority with version-matching enforcement intact.
Regression Tests
tests/test_env.py
Added comprehensive test suite for _get_cubin_dir() priority logic using importlib-based mocking to avoid CUDA dependencies. Four test cases verify correct behavior: env var override, package fallback, env var with missing package, and default cache directory fallback.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • yzh119

Poem

🐰 Hops through cubins with glee,
Priority fixed, now let it be!
Env vars first, that's the way,
Non-root containers work today!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: reordering priority so FLASHINFER_CUBIN_DIR env var overrides the flashinfer-cubin package path.
Description check ✅ Passed The description comprehensively covers the problem, root cause, fix approach, testing, and impact, following the template's spirit with context, testing notes, and linked issues.
Linked Issues check ✅ Passed The code changes directly address the root cause in issue #2976 by reordering _get_cubin_dir() to check FLASHINFER_CUBIN_DIR first, and regression tests verify all four priority scenarios.
Out of Scope Changes check ✅ Passed All changes are in scope: env.py reorders cubin directory priority, and test_env.py adds regression tests for the priority logic. No unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the cubin directory resolution logic in flashinfer/jit/env.py to prioritize the FLASHINFER_CUBIN_DIR environment variable over the installed package. It also introduces a new test file, tests/test_env.py, to verify this priority and fallback behavior. Feedback was provided to improve test isolation by ensuring the module under test is correctly saved and restored in sys.modules within the test utility function.

Comment thread tests/test_env.py

stubs["flashinfer.compilation_context"].CompilationContext = _Stub

saved = {k: sys.modules.get(k) for k in stubs}
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.

medium

The current implementation of _load_env_module does not save and restore the state of sys.modules["flashinfer.jit.env"]. This can lead to test isolation issues if other tests in the same process attempt to import this module, as they will receive the mocked version instead of the real one. It is safer to include the module being tested in the saved dictionary so it can be properly cleaned up in the finally block.

Suggested change
saved = {k: sys.modules.get(k) for k in stubs}
modules_to_save = list(stubs.keys()) + ["flashinfer.jit.env"]
saved = {k: sys.modules.get(k) for k in modules_to_save}

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@tests/test_env.py`:
- Around line 38-56: The helper _load_env_module mutates sys.modules by
inserting "flashinfer.jit.env" but never restores any prior entry, causing
cross-test contamination when _env is created at import time; update
_load_env_module to save the original value of "flashinfer.jit.env" before
assigning mod (e.g. original_env = sys.modules.get("flashinfer.jit.env") or
include that key in the saved dict) and in the finally block restore it exactly
as you do for other stubs (if original is None pop the key, else set it back),
ensuring "flashinfer.jit.env" is returned to its pre-call state and preventing
stale module reuse by _env.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36af5a7d-350b-4068-98b8-988014915f26

📥 Commits

Reviewing files that changed from the base of the PR and between 57c37bf and 11062e7.

📒 Files selected for processing (2)
  • flashinfer/jit/env.py
  • tests/test_env.py

Comment thread tests/test_env.py
Comment on lines +38 to +56
saved = {k: sys.modules.get(k) for k in stubs}
sys.modules.update(stubs)
try:
spec = importlib.util.spec_from_file_location(
"flashinfer.jit.env", str(_REPO_ROOT / "flashinfer" / "jit" / "env.py")
)
mod = importlib.util.module_from_spec(spec)
sys.modules["flashinfer.jit.env"] = mod
spec.loader.exec_module(mod)
return mod
finally:
for k, v in saved.items():
if v is None:
sys.modules.pop(k, None)
else:
sys.modules[k] = v


_env = _load_env_module()
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.

⚠️ Potential issue | 🟠 Major

Prevent cross-test contamination from sys.modules mutation.

Line 45 installs flashinfer.jit.env into sys.modules, but _load_env_module() never restores any preexisting entry for that key. Because _env is created at import time (Line 56), later tests can accidentally reuse this stub-loaded module.

Proposed fix
 def _load_env_module():
@@
-    saved = {k: sys.modules.get(k) for k in stubs}
+    saved = {k: sys.modules.get(k) for k in stubs}
+    saved_env_module = sys.modules.get("flashinfer.jit.env")
     sys.modules.update(stubs)
     try:
         spec = importlib.util.spec_from_file_location(
             "flashinfer.jit.env", str(_REPO_ROOT / "flashinfer" / "jit" / "env.py")
         )
         mod = importlib.util.module_from_spec(spec)
         sys.modules["flashinfer.jit.env"] = mod
         spec.loader.exec_module(mod)
         return mod
     finally:
+        if saved_env_module is None:
+            sys.modules.pop("flashinfer.jit.env", None)
+        else:
+            sys.modules["flashinfer.jit.env"] = saved_env_module
         for k, v in saved.items():
             if v is None:
                 sys.modules.pop(k, None)
             else:
                 sys.modules[k] = v
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_env.py` around lines 38 - 56, The helper _load_env_module mutates
sys.modules by inserting "flashinfer.jit.env" but never restores any prior
entry, causing cross-test contamination when _env is created at import time;
update _load_env_module to save the original value of "flashinfer.jit.env"
before assigning mod (e.g. original_env = sys.modules.get("flashinfer.jit.env")
or include that key in the saved dict) and in the finally block restore it
exactly as you do for other stubs (if original is None pop the key, else set it
back), ensuring "flashinfer.jit.env" is returned to its pre-call state and
preventing stale module reuse by _env.

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.

FLASHINFER_CUBIN_DIR env var ignored when flashinfer-cubin package is installed — breaks non-root containers

1 participant