Everything on this machine works now. Six standalone image and video apps, a LoRA trainer, an ONNX-based transcriber, all sharing one RTX 5090 on Windows 11, all starting and stopping cleanly from bat files. Getting there meant a full uninstall of one CUDA toolkit, a second toolkit installed beside the one I kept, a manual PATH surgery the cuDNN installer should have done itself, and one library that silently downgraded my torch build the moment I installed it.
If you just bought a 5090 for local AI work, this is the writeup I wanted and couldn't find. Nothing here is theory. Every path and version number below is running on my desk right now.
The one fact that drives everything: sm_120
The 5090 is Blackwell, compute capability sm_120. Older PyTorch wheels don't carry kernels for it. Install a wheel built for an earlier CUDA target and you get the classic failure: torch imports fine, CUDA reports available, and then the first real kernel launch dies with a no-kernel-image error. The card is fine. The wheel just doesn't know your architecture exists.
The rule: PyTorch built against cu128 or cu130. Nothing older. On my box the working pairs are torch 2.11.0+cu130 and torch 2.10.0+cu130, depending on the app. When you install, spell the index URL out explicitly and check the suffix on the installed version string afterward. "pip show torch" reporting a version without a +cu128 or +cu130 suffix means you got a CPU wheel or a stale CUDA build, and you will find out the hard way at first inference.
Check this before anything else. Half the mystery crashes people report on new-architecture cards are just this one mismatch wearing different costumes.
The xformers trap
This is the one that costs people an afternoon, because the failure arrives disguised as success.
You stand up ComfyUI or any diffusion stack, torch 2.11.0+cu130 is installed and working, generation runs. Then you install xformers for the memory-efficient attention, the way every tutorial from the last three years tells you to. Pip resolves dependencies, decides your torch is incompatible with the xformers wheel it selected, and quietly replaces your torch with an older build that has no sm_120 kernels. No warning that matters, just a long pip log most people don't read. Next launch, the app that worked an hour ago crashes at the first sampling step.
My fix was to stop using xformers entirely on this card. SageAttention 2.2.0 covers the attention optimization without touching the torch install, and it behaves on Blackwell. The rule I now follow on every app: after installing anything attention-related, run "pip show torch" again and confirm the version string did not move. If a package manager can change your torch build as a side effect, treat every install as a suspect until proven otherwise.
CUDA 12.9 and 13.2, side by side, on purpose
Here is the part nobody tells you: one CUDA toolkit is not enough, because your apps do not agree on a major version.
PyTorch cu130 builds want the CUDA 13 runtime. But ONNX Runtime with the CUDA execution provider (version 1.24 in my case, driving a speech-to-text app) loads CUDA 12 DLLs by name. And the names are version-suffixed: it asks the OS loader for cudart64_12.dll, cublas64_12.dll, cufft64_11.dll. A CUDA 13 install gives you cudart64_13.dll. The loader will not squint and accept a neighbor. The app just reports that CUDA is unavailable and falls back to CPU, or refuses to start.
So this machine runs both toolkits, installed side by side:
- CUDA 13.2 at "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.2" is primary. CUDA_PATH points here, and everything torch-based resolves against it.- CUDA 12.9.1 at "...\CUDA\v12.9" exists purely to serve the version-suffixed CUDA 12 DLLs to ONNX Runtime and anything else still living on the 12.x runtime.One sharp edge inside that second install: the 12.9 DLLs sit in "bin" directly, not in a "bin\x64" subfolder, which differs from where some tooling expects them. When an app claims a DLL is missing, do not trust your assumptions about the layout. Open the folder and look. The general lesson: before installing any CUDA-dependent app, find out which runtime major version it actually loads. The DLL names tell you. An app hunting for cudart64_12.dll will never be satisfied by a CUDA 13 toolkit, no matter how new and shiny. And keep the count at exactly the versions you need. I briefly had CUDA 13.1 on this box too. Three toolkits meant three sets of PATH entries and env vars fighting over resolution order, so 13.1 got fully removed: directory, PATH entries, environment variables, all of it. Two toolkits with clear jobs beat three with overlapping ones. ## cuDNN: the installer does not finish the job cuDNN 9.20 installs to "C:\Program Files\NVIDIA\CUDNN\v9.20" and, helpfully, ships per-CUDA-version DLL directories: "bin\13.2\x64" for the CUDA 13 side and "bin\12.9\x64" for the CUDA 12 side. That layout is exactly what a dual-toolkit machine needs. What the installer does not do is add either directory to your system PATH. Nothing warns you. Apps that need cudnn64_9.dll simply fail to find it, and the error messages rarely say so plainly. I added both directories to the system PATH by hand, and a whole category of intermittent startup failures ended that day. One related Windows note: system-level environment changes need an elevated shell. My reliable pattern is a small .ps1 script invoked with "Start-Process -Verb RunAs" rather than trying to elevate inline, which fails in quiet and creative ways. ## Compiling extensions: MSVC meets the CCCL headers Sooner or later on a card this new, you compile something from source, because the prebuilt wheel for your exact torch and CUDA combination does not exist yet. On Windows with CUDA 13.2 and MSVC 2019, the CCCL headers require the standards-conforming preprocessor, and the default MSVC preprocessor is not it. The build fails deep in template code with errors that suggest anything except the actual cause. The fix is two flags: add "/Zc:preprocessor" to the C++ compiler args, and "-Xcompiler=/Zc:preprocessor" to the NVCC args so the host-compiler passes get it too. Miss the second one and you get a build that half succeeds, which is worse than one that fails honestly. ## Per-app isolation, or how six apps share one card without sharing dependencies Every GPU app on this machine gets its own environment. No shared site-packages, no global installs, no exceptions. ComfyUI runs a venv on Python 3.13.3 with torch 2.11.0+cu130. The video generation app runs conda with Python 3.11.9 and torch 2.10.0+cu130. The 3D generation app, the training tools, each one isolated the same way. When one app's dependency resolver has a bad day, the blast radius is one folder. Each app carries four bat files: start, stop, status, update. Boring on purpose. The start script points at the environment's python.exe by full path and binds the app to its own port. Which brings up the conda trap that will bite anyone scripting Windows automation: conda environments created this way do not ship an activate.bat. Every tutorial that says "call activate envname" writes a script that dies on this box. The fix is to never activate at all. Call "C:\AppName\env\python.exe" by absolute path and the whole class of activation failure disappears, in scripts, in schedulers, in anything unattended. Above the bat files sits a small FastAPI dashboard that starts, stops, and health-checks the fleet, around 19 managed apps at last count, with a mutex so two heavy jobs cannot claim the card at once. But the dashboard is a convenience. The bat files are the contract, and each one works standalone. ## Process hygiene: dead processes still hold your VRAM The 5090 has 32 GB of VRAM and it is still not enough to waste. The failure mode that teaches you this: you stop an app, or it crashes, and the process dies badly, leaving allocated GPU memory behind. The next app launches, tries to claim memory the ghost still owns, and falls over with an out-of-memory error on a card that looks idle. Two habits fixed it permanently:
- Run "nvidia-smi" before starting any GPU work and after stopping any app. Stale python processes holding VRAM get killed before anything else launches.- Hunt zombies by executable path, not by port. A crashed process is not listening on its port anymore, but it is absolutely still holding memory. In PowerShell: "Get-Process python | Where-Object {$.Path -like 'AppName'} | Stop-Process -Force". Port-based detection misses exactly the processes you most need to kill.Two smaller Windows-flavored footguns in the same family. Stale __pycache_ directories can serve old bytecode after you edit a module, producing phantom 404s and behavior from code you already deleted, so when an edit refuses to take effect, delete the pycache folders before doubting your own diff. And when a port refuses to bind, "netstat -ano" with a filter on the port number finds the owning PID faster than any amount of guessing. ## The short version
- PyTorch cu128 or cu130 only. Verify the +cu suffix on the installed version, not just that import succeeds.- Skip xformers, it will downgrade your torch underneath you. SageAttention 2.2.0 does the job on Blackwell.- Read the DLL names your apps load. cudart64_12.dll means you need a CUDA 12 toolkit installed beside your CUDA 13 one. The suffix is the contract.- Add the cuDNN DLL directories to PATH yourself. The installer will not.- Compiling with MSVC 2019 and CUDA 13.2: "/Zc:preprocessor" for the compiler, "-Xcompiler=/Zc:preprocessor" for NVCC.- One environment per app, called by absolute python.exe path. Conda on Windows has no activate.bat, stop writing scripts that assume it does.- Trust "nvidia-smi", not your process list. Dead processes hold VRAM, and killing by executable path is the only reliable sweep.None of this is hard once you know it. All of it is invisible until you do. The card itself has been flawless, the ecosystem just needed a few months to catch up to sm_120, and the machine that came out the other side runs a real workload every day. The basics, dialed.
Top comments (0)