Repository navigation
Conversation
A pip-installed framework depends on the CUDA libraries in its own Python environment. Transformer Engine searched the dynamic linker's default paths first, so a host-wide cuDNN replaced the one that torch needs. With torch 2.15 and an older system cuDNN, this raises "cuDNN version incompatibility". Keep explicit locations first: the library-specific variables, CUDA_HOME, CUDA_PATH, /usr/local/cuda, and LD_LIBRARY_PATH. Then search the Python environment, and use the linker default last. LD_LIBRARY_PATH is now read directly, so it also finds versioned libraries that have no unversioned symlink. Signed-off-by: Bruno Volpato <brunocvcunha@gmail.com>
Importing Transformer Engine raises "curand shared object not found" on a host without the CUDA toolkit when PyTorch 2.15 is installed. PyTorch 2.15 removed curand from its cuda-toolkit extras, and JAX does not install it. Transformer Engine only uses cuRAND's device-side headers. The core library does not link libcurand and calls none of its host functions, so the import does not need to load it. Decide whether the toolkit is present from NVRTC alone. Signed-off-by: Bruno Volpato <brunocvcunha@gmail.com>
5 of 13 tasks
bvolpato
marked this pull request as ready for review
November 3, 2026 02:52
Contributor
[Medium impact] The PR appears safe to merge; the previous token-path finding is fixed. SummaryThe PR puts Python-provided CUDA libraries ahead of default system locations while keeping explicit environment choices first.
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Load CUDA library] --> B[Explicit library and toolkit paths]
B -->|Not found| C[Selected LD_LIBRARY_PATH entries]
C -->|Not found| D[Python packages]
D -->|Not found| E[Default linker search]
E -->|Not found| F[Raise missing-library error]
Reviews (3) · Last reviewed commit: "[Common] Limit LD_LIBRARY_PATH token han..." · Reviewed by Greptile |
Keep three cases that the previous search changes altered: - Only the dynamic linker can expand tokens such as $ORIGIN in LD_LIBRARY_PATH, so leave those entries to the linker. Otherwise, the Python packages take priority over the selected location. - Follow the unversioned name in an LD_LIBRARY_PATH entry when it exists, because it selects a version. Use the newest versioned name only when it does not exist. - When NVRTC comes from a Python package, the other libraries can still come from the system. Load cuBLAS and cudart from Python packages only if they are there, and leave the rest to the dynamic linker. Remove the second cuDNN load, which is redundant for a Python cuDNN and otherwise maps another copy. Signed-off-by: Bruno Volpato <brunocvcunha@gmail.com>
An LD_LIBRARY_PATH entry with a token such as $ORIGIN sent the search to the dynamic linker's bare-name lookup. That lookup also searches the default locations, so an unrelated token entry could load a host-wide cuDNN ahead of the Python package and bring back the version mismatch. Expand $ORIGIN to the executable's directory, as the linker does for this variable, and pass entries with other tokens to dlopen as a path. If an entry does not have the library, the search continues to the next location. Signed-off-by: Bruno Volpato <brunocvcunha@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fix two ways that the runtime CUDA library search breaks environments where a pip-installed framework supplies the CUDA libraries.
A host-wide cuDNN replaces the cuDNN that the framework needs. The
CDLL("libcudnn.so")fallback is described as anLD_LIBRARY_PATHsearch, but it also searches the dynamic linker's default locations, and it runs before the Python environment. PyPItorchpins its ownnvidia-cudnn-cu13, so on a host with an older system cuDNN it fails with:With JAX, the same search maps two copies of cuDNN into one process.
The import also requires
libcurand. PyTorch 2.15 removedcurandfrom itscuda-toolkitextras, and JAX does not install it, so on a host without the CUDA toolkit the import fails withcurand shared object not found. Transformer Engine only uses cuRAND's device-side headers. The core library does not linklibcurandand calls none of its host functions.Related to #2373 and #2297, which made
LD_LIBRARY_PATHtake priority over Python packages. This PR keeps that priority.Type of change
Changes
<LIBRARY>_HOME,<LIBRARY>_PATH,CUDA_HOME,CUDA_PATH,/usr/local/cuda,LD_LIBRARY_PATH, the Python environment, and then the dynamic linker's default locations.LD_LIBRARY_PATHdirectly, so that it also finds versioned libraries such aslibcudnn.so.9. The pip packages have no unversioned symlink, so the previous lookup could not find them there. An entry's unversioned name still takes priority when it exists.$ORIGINexpands to the executable's directory, and an entry with another token, such as$LIB, goes todlopenas a path. An entry that does not have the library does not affect the search.PyTorch preloads the cuDNN from its own Python package, so when the environment selects the system cuDNN, PyTorch's copy is mapped too and PyTorch rejects the older version. That behavior is not new.
One behavior changes on purpose. If a framework uses a system cuDNN and an unrelated pip cuDNN package is also installed, Transformer Engine now loads the pip package unless the environment selects a location.
CUDNN_PATHorLD_LIBRARY_PATHselects the system copy.Before and after
These runs used one NVIDIA B200 with system cuDNN 9.20 and PyTorch 2.15.0+cu132, which installs cuDNN 9.26.
cuDNN version incompatibilityLD_LIBRARY_PATHset to pip cuDNNcuDNN version incompatibilityCUDNN_PATHset to pip cuDNNLD_LIBRARY_PATHorCUDNN_PATHset to system cuDNNtransformer_engine.commoncurand shared object not foundcurand shared object not foundLD_LIBRARY_PATHentry with$ORIGINor$LIBthat selects system cuDNNLD_LIBRARY_PATHentry with$ORIGINor$LIBthat has no cuDNNcuDNN version incompatibilityLD_LIBRARY_PATHentry whoselibcudnn.soselects one of two versionslibcudnn.soValidation
The source builds targeted
100awith CUDA 13.2, PyTorch 2.15.0+cu132, cuDNN 9.26, FlashAttention 2.8.4, and JAX 0.12.0.1. The base wasb0219803.test_sanity.pyfail when the search order or the cuRAND load is reverted, or when theLD_LIBRARY_PATHname and token handling is removed, and they pass with this change.test_torch_compile.py([PyTorch] torch.compile fails on FusedAttnBackend IntEnum comparisons #3716),test_dot_product_attention_score_mod([PyTorch] Keep Flex Attention score_mod graphs on the cuDNN backend #3796), and FP32 numerics cases ([CI] Disable TF32 for the L0 PyTorch numerics tests #3797).test_layer.pyandtest_fused_attn_score_mod.pyfound no failures in the default environment, with the system cuDNN present, before the last commit.test_fused_attn.pyfound no failures before the last two commits. The last commit only changesLD_LIBRARY_PATHentries that contain tokens, and JAX import was rechecked after it.test_sanity.py,test_numerics.py,tests/pytorch/nvfp4,tests/pytorch/mxfp8, andtest_quantized_tensor.pyfound no failures before the last commit, withNVIDIA_TF32_OVERRIDE=0set. JAX imported and ran a basic operation. The no-toolkit import and a forward pass were rechecked on the final code.Pylint reported no issues for the changed module, and the repository hooks passed. A100, H100, aarch64, and NGC images, where the framework uses the system cuDNN, were not tested. Release wheels were not rebuilt with this change.
Checklist: