From e1de0446a0382d5ac34095465aac6be3aa804421 Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Fri, 20 Mar 2026 13:05:26 +0100 Subject: [PATCH 1/4] Fix native library loader silently failing when CUDA DLLs are missing Change all 'ok = TryLoadNativeLibraryByName(...)' calls to 'ok &= ...' so that failures accumulate instead of being overwritten by subsequent successful loads. Initialize 'ok = true' before the loading chain. Previously, each load call overwrote the result of the previous one, so if an early CUDA dependency (e.g. cudnn_adv64_9) failed to load but LibTorchSharp succeeded, 'ok' would be true. This caused: - nativeBackendCudaLoaded set to true despite missing dependencies - The fallback loading path was skipped - The diagnostic trace (StringBuilder) was discarded - Subsequent load attempts were skipped entirely - CUDA operations failed later with cryptic errors Now any single load failure keeps 'ok' as false, ensuring the fallback path is attempted and the full diagnostic trace is preserved in error messages. Fixes dotnet/TorchSharp#1545 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/TorchSharp/Torch.cs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index 32dbdb4b6..d6f9b3287 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -117,7 +117,7 @@ private static void LoadNativeBackend(bool useCudaBackend, out StringBuilder? tr trace = null; if (!alreadyLoaded) { - bool ok; + bool ok = true; trace = new StringBuilder(); trace.AppendLine($""); trace.AppendLine($"TorchSharp: LoadNativeBackend: Initialising native backend, useCudaBackend = {useCudaBackend}"); @@ -135,27 +135,27 @@ private static void LoadNativeBackend(bool useCudaBackend, out StringBuilder? tr // Preloading these DLLs on windows seems to iron out problems where one native DLL // requests a load of another through dynamic linking techniques. // - ok = TryLoadNativeLibraryByName("cudnn_adv64_9", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cudnn_cnn64_9", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cudnn_ops64_9", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cudnn_graph64_9.dll", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cudnn_heuristic64_9.dll", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cudnn_engines_precompiled64_9.dll", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cudnn_engines_runtime_compiled64_9.dll", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("nvrtc-builtins64_128", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("caffe2_nvrtc", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("nvrtc64_120_0", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cublasLt64_12", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cufft64_11", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cusparse64_12", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("cusolver64_11", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_adv64_9", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_cnn64_9", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_ops64_9", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_graph64_9.dll", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_heuristic64_9.dll", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_engines_precompiled64_9.dll", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cudnn_engines_runtime_compiled64_9.dll", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("nvrtc-builtins64_128", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("caffe2_nvrtc", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("nvrtc64_120_0", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cublasLt64_12", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cufft64_11", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cusparse64_12", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("cusolver64_11", typeof(torch).Assembly, trace); } - ok = TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } else { - ok = TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } trace.AppendLine($" Result from regular native load of LibTorchSharp is {ok}"); From e3ce275340abcec7c707298459edce1c5fe0c1ce Mon Sep 17 00:00:00 2001 From: Stefan-Alin Pahontu <56953855+alinpahontu2912@users.noreply.github.com> Date: Fri, 20 Mar 2026 16:33:32 +0100 Subject: [PATCH 2/4] Update src/TorchSharp/Torch.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/TorchSharp/Torch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index d6f9b3287..931f5752a 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -158,7 +158,7 @@ private static void LoadNativeBackend(bool useCudaBackend, out StringBuilder? tr ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } - trace.AppendLine($" Result from regular native load of LibTorchSharp is {ok}"); + trace.AppendLine($" Result from regular native load of backend libraries (CUDA preloads + torch_* + LibTorchSharp) is {ok}"); // Try dynamic load from package directories if (!ok) { From 26d09588fb058f28087c7cdeae4b628755fe1369 Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Tue, 24 Mar 2026 13:34:02 +0100 Subject: [PATCH 3/4] Fix native loader: only LibTorchSharp determines load success The previous fix changed simple assignments (ok =) to compound AND (ok &=) for all native library loads. This broke CPU-only systems because torch_cuda failing would permanently set ok=false, even when LibTorchSharp loaded successfully, triggering a NotSupportedException. Changes: - CUDA preloads (cudnn, nvrtc, etc.): fire-and-forget, failures are non-fatal and only logged via trace - torch_cuda / torch_cpu: fire-and-forget warmup loads for dependency resolution; their result doesn't gate success - LibTorchSharp: the only critical load that determines ok - TryInitializeDeviceType: catch NotSupportedException to prevent static constructor crashes - Static constructor: fall back to CPU backend when CUDA is unavailable Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tensor/Factories/Tensor.Factories.cs | 5 ++- src/TorchSharp/Torch.cs | 45 +++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/TorchSharp/Tensor/Factories/Tensor.Factories.cs b/src/TorchSharp/Tensor/Factories/Tensor.Factories.cs index 572e0da4f..535384a26 100644 --- a/src/TorchSharp/Tensor/Factories/Tensor.Factories.cs +++ b/src/TorchSharp/Tensor/Factories/Tensor.Factories.cs @@ -649,7 +649,10 @@ private static void ValidateIntegerRange(long value, ScalarType dtype, string ar static torch() { deleters = new ConcurrentDictionary(); - TryInitializeDeviceType(DeviceType.CUDA); + if (!TryInitializeDeviceType(DeviceType.CUDA)) { + // CUDA not available, ensure CPU backend is loaded + LoadNativeBackend(false, out _); + } } #endregion } diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index 931f5752a..ea10f4618 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -135,27 +135,29 @@ private static void LoadNativeBackend(bool useCudaBackend, out StringBuilder? tr // Preloading these DLLs on windows seems to iron out problems where one native DLL // requests a load of another through dynamic linking techniques. // - ok &= TryLoadNativeLibraryByName("cudnn_adv64_9", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cudnn_cnn64_9", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cudnn_ops64_9", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cudnn_graph64_9.dll", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cudnn_heuristic64_9.dll", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cudnn_engines_precompiled64_9.dll", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cudnn_engines_runtime_compiled64_9.dll", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("nvrtc-builtins64_128", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("caffe2_nvrtc", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("nvrtc64_120_0", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cublasLt64_12", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cufft64_11", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cusparse64_12", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("cusolver64_11", typeof(torch).Assembly, trace); + // These are optional preloads to help Windows resolve transitive native dependencies. + // Failures here are non-fatal -- the critical loads are torch_cuda and LibTorchSharp below. + TryLoadNativeLibraryByName("cudnn_adv64_9", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cudnn_cnn64_9", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cudnn_ops64_9", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cudnn_graph64_9.dll", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cudnn_heuristic64_9.dll", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cudnn_engines_precompiled64_9.dll", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cudnn_engines_runtime_compiled64_9.dll", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("nvrtc-builtins64_128", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("caffe2_nvrtc", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("nvrtc64_120_0", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cublasLt64_12", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cufft64_11", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cusparse64_12", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("cusolver64_11", typeof(torch).Assembly, trace); } - ok &= TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); + ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } else { - ok &= TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); - ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); + TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); + ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } trace.AppendLine($" Result from regular native load of backend libraries (CUDA preloads + torch_* + LibTorchSharp) is {ok}"); @@ -345,7 +347,12 @@ public static bool TryInitializeDeviceType(DeviceType deviceType) return false; } - LoadNativeBackend(deviceType == DeviceType.CUDA, out _); + try { + LoadNativeBackend(deviceType == DeviceType.CUDA, out _); + } catch (NotSupportedException) { + return false; + } + if (deviceType == DeviceType.CUDA) { return cuda.CallTorchCudaIsAvailable(); } else { From c195877c3c67009280f49fcc8d831c6ecd2b4ecf Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Tue, 28 Apr 2026 11:38:50 +0200 Subject: [PATCH 4/4] Use ok &= for native library loads to accumulate failures Change all critical 'ok = TryLoadNativeLibraryByName(...)' calls to 'ok &= ...' so that a failure in torch_cuda/torch_cpu is not silently overwritten by a subsequent successful LibTorchSharp load. With ok initialized to true, any single failure keeps ok as false, ensuring the fallback loading path is attempted and the full diagnostic trace is preserved. Fixes #1545 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/TorchSharp/Torch.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index ea10f4618..007f70cc9 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -153,11 +153,11 @@ private static void LoadNativeBackend(bool useCudaBackend, out StringBuilder? tr TryLoadNativeLibraryByName("cusolver64_11", typeof(torch).Assembly, trace); } - TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } else { - TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); - ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); + ok &= TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } trace.AppendLine($" Result from regular native load of backend libraries (CUDA preloads + torch_* + LibTorchSharp) is {ok}");