faster-whisper’s “Could Not Load Library libcudnn” Error
9 min read · updated August 11, 2026
The import succeeds, the model loads, and the process dies the moment it touches the GPU. The library it is looking for is a specific major version of cuDNN, and which one depends on a CTranslate2 version boundary that nothing in the error mentions.
The two strings
Which one you get tells you which side of the boundary you are on. The cuDNN 8 form:
Could not load library libcudnn_ops_infer.so.8. Error: libcudnn_ops_infer.so.8: cannot open shared object file: No such file or directory
and the cuDNN 9 form, which names several candidates it tried:
Unable to load any of {libcudnn_cnn.so.9.1.0, libcudnn_cnn.so.9.1,
libcudnn_cnn.so.9, libcudnn_cnn.so}
Invalid handle. Cannot load symbol cudnnCreateConvolutionDescriptorThe exact minor versions in the second block depend on what cuDNN 9 build is expected, so read yours rather than matching it to the one here; what identifies it is the shape — a list of candidate filenames, all cuDNN 9, followed by a symbol that could not be loaded.
The first is reported against faster-whisper and its downstream projects — whisperX issue 1027 quotes it directly — and it is usually followed by the process aborting rather than raising a Python exception, which is why a try around the call does not save you.
Why it fails mid-run and not at import
faster-whisper is a Python wrapper over CTranslate2, a C++ inference engine. CTranslate2 links cuDNN dynamically and resolves it lazily — the shared object is opened the first time a GPU operation needs it, not when the Python module is imported and not when the model is constructed.
That lazy resolution is the whole reason this is confusing. Everything up to and including WhisperModel("large-v3", device="cuda") succeeds, so the environment looks correct; the failure lands on the first transcribe() call, which reads like an audio problem. It is not. Nothing about the audio matters and the same call on device="cpu" works fine, which is a fast way to confirm the diagnosis.
The version boundary that causes it
CTranslate2 changed which cuDNN major version it builds against, and the change is a hard boundary rather than a gradual one:
- CTranslate2 4.4.0 and earlier link cuDNN 8, and look for
libcudnn_ops_infer.so.8and its siblings. - CTranslate2 4.5.0 and later moved to cuDNN 9, which in turn requires a CUDA 12.3 or newer environment. The upstream discussion is CTranslate2 issue 1780.
- CTranslate2 3.24.0 is the version people pin for a CUDA 11 machine.
The collision comes from PyTorch, which most environments also have. Recent PyTorch wheels bundle cuDNN 9 inside site-packages/nvidia/cudnn/lib. Install faster-whisper alongside a current torch and pip resolves both happily — but if the CTranslate2 that lands wants cuDNN 8 and the only cuDNN present is 9, the import still succeeds and the runtime cannot find its file. The reverse pairing produces the second error string.
Find out what you have before changing anything:
pip show ctranslate2 torch | grep -E 'Name|Version' python -c "import nvidia.cudnn, os; print(os.path.dirname(nvidia.cudnn.__file__))" ls $(python -c "import nvidia.cudnn,os;print(os.path.dirname(nvidia.cudnn.__file__))")/lib
Two details make this worse than an ordinary version conflict. The first is that neither package declares the incompatibility, because neither depends on the other — they depend on the same system library through different routes, and pip has no visibility into that. The second is that the file which satisfies one of them is physically present on disk for the other; a machine with a current PyTorch has a complete cuDNN 9 installation sitting inside site-packages, and the process that needs cuDNN 8 walks straight past it.
It is also worth knowing that the cuDNN sub-libraries are separate files. libcudnn.so being present proves nothing; the specific operation library named in the message — the ops or convolution component — is what failed to open, and it can be missing from an otherwise complete-looking installation, particularly one assembled from a partial system package rather than from a wheel.
Three fixes, and how to pick
- Pin CTranslate2 to match the cuDNN you have. The most reliable fix and the one to reach for first. If your environment has cuDNN 8, install
ctranslate2==4.4.0(CUDA 12) orctranslate2==3.24.0(CUDA 11). Pin it in the requirements file so the next install does not undo it. - Install the cuDNN your CTranslate2 wants. The
nvidia-cudnn-cu12package supplies it. This is the right choice when something else in the environment needs a newer CTranslate2 and you cannot pin backwards. - Point the loader at the libraries already present. Frequently the correct cuDNN is on disk inside the torch install and simply is not on the search path. Adding it costs nothing and does not change any package version.
# option 1 pip install --force-reinstall ctranslate2==4.4.0 # option 3 (Linux) export LD_LIBRARY_PATH=$(python -c \ "import nvidia.cudnn, os; print(os.path.join(os.path.dirname(nvidia.cudnn.__file__), 'lib'))"):$LD_LIBRARY_PATH python transcribe.py
Which to pick comes down to who else is in the environment. If faster-whisper is the only thing there, pin CTranslate2 and stop thinking about it — option 1 is stable and needs no runtime configuration. If PyTorch is present for another reason, option 3 is the least invasive, because it changes nothing that pip knows about and survives an unrelated upgrade. Option 2 is for the case where something else genuinely requires a newer CTranslate2, and it commits you to managing two cuDNN installations, which is a thing to do deliberately rather than by accident.
Option 3 has to be set in the environment that launches the process, not inside Python — the dynamic loader reads it at process start, so setting os.environ from within the script is too late. That detail accounts for a good share of the reports where the fix is said not to work.
Verifying without transcribing an hour of audio
Because the failure is lazy, you want a check that reaches the GPU path in a second or two. A short synthetic clip is enough — the point is to force one GPU inference, not to test accuracy:
python - <<'PY'
from faster_whisper import WhisperModel
m = WhisperModel("tiny", device="cuda", compute_type="float16")
segments, info = m.transcribe("short.wav")
print(info.language, [s.text for s in segments][:1])
PYIf that prints, the library resolution is fixed and you can move to the model size you actually wanted. If it aborts with the same message, the change did not take effect in the environment that ran it — check you are in the virtual environment you edited, and that a shell variable set in another terminal is not the thing you are relying on. For the alternative runtime that avoids the whole dependency chain, see whisper.cpp, which is a single binary with no Python or cuDNN in the picture.