From cc3ed639bbc2dc6df8181909e4d1345506b410c9 Mon Sep 17 00:00:00 2001 From: Jim Park Date: Sun, 15 Mar 2026 14:22:22 -0700 Subject: [PATCH 1/3] fix: prevent uncatchable native crash when CUDA libs present but ORT lacks CUDA provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onnxruntime-node versions before 1.24.0 are CPU-only and do not ship libonnxruntime_providers_cuda.so. When system CUDA libraries (e.g. libcublasLt.so.12) are detected, isCudaAvailable() returns true and the embedder requests the CUDA execution provider. Since the provider binary doesn't exist in the package, ONNX Runtime crashes at the native level (provider_bridge_ort.cc), which is uncatchable by the JS try/catch fallback — killing the entire process. This commit: - Adds onnxruntime-node ^1.24.0 as an explicit dependency (first version to ship CUDA provider binaries for Linux x64) - Adds hasOrtCudaProvider() check that verifies the CUDA provider .so exists in the onnxruntime-node package before attempting CUDA, so the embedder gracefully falls back to CPU on older ORT versions Fixes the crash at 92% "Loading embedding model..." on Linux systems with CUDA toolkit installed. Also related to #165. Co-Authored-By: Claude Opus 4.6 (1M context) --- gitnexus/package.json | 1 + gitnexus/src/core/embeddings/embedder.ts | 32 +++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/gitnexus/package.json b/gitnexus/package.json index 5897fb865..e143a3a15 100644 --- a/gitnexus/package.json +++ b/gitnexus/package.json @@ -49,6 +49,7 @@ }, "dependencies": { "@huggingface/transformers": "^3.0.0", + "onnxruntime-node": "^1.24.0", "@modelcontextprotocol/sdk": "^1.0.0", "cli-progress": "^3.12.0", "commander": "^12.0.0", diff --git a/gitnexus/src/core/embeddings/embedder.ts b/gitnexus/src/core/embeddings/embedder.ts index c3c0b5f88..65ecd7a3f 100644 --- a/gitnexus/src/core/embeddings/embedder.ts +++ b/gitnexus/src/core/embeddings/embedder.ts @@ -17,18 +17,44 @@ if (!process.env.ORT_LOG_LEVEL) { import { pipeline, env, type FeatureExtractionPipeline } from '@huggingface/transformers'; import { existsSync } from 'fs'; import { execFileSync } from 'child_process'; -import { join } from 'path'; +import { join, dirname } from 'path'; +import { createRequire } from 'module'; import { DEFAULT_EMBEDDING_CONFIG, type EmbeddingConfig, type ModelProgress } from './types.js'; +/** + * Check whether the onnxruntime-node package ships the CUDA execution provider. + * Versions before 1.24.0 are CPU-only and do not include libonnxruntime_providers_cuda.so. + * Attempting CUDA on those versions causes an uncatchable native crash. + */ +function hasOrtCudaProvider(): boolean { + try { + const require = createRequire(import.meta.url); + const ortPath = dirname(require.resolve('onnxruntime-node/package.json')); + // Check both napi-v6 (>=1.24) and napi-v3 (<=1.21) layouts + return existsSync(join(ortPath, 'bin', 'napi-v6', 'linux', 'x64', 'libonnxruntime_providers_cuda.so')) || + existsSync(join(ortPath, 'bin', 'napi-v3', 'linux', 'x64', 'libonnxruntime_providers_cuda.so')); + } catch { + return false; + } +} + /** * Check whether CUDA libraries are actually available on this system. * ONNX Runtime's native layer crashes (uncatchable) if we attempt CUDA * without the required shared libraries, so we probe first. * - * Checks the dynamic linker cache (ldconfig) which covers all architectures - * and install paths, then falls back to CUDA_PATH / LD_LIBRARY_PATH env vars. + * Checks both: + * 1. That system CUDA libraries (libcublasLt) are present + * 2. That onnxruntime-node ships the CUDA execution provider binary + * + * Both conditions must be true — system CUDA libs alone are not enough + * if onnxruntime-node is a CPU-only build (versions < 1.24.0). */ function isCudaAvailable(): boolean { + // First, verify onnxruntime-node has the CUDA provider binary. + // Without this, requesting CUDA causes an uncatchable native crash. + if (!hasOrtCudaProvider()) return false; + // Primary: query the dynamic linker cache — covers all architectures, // distro layouts, and custom install paths registered with ldconfig try { From d682b0ff20b7cbffd0df61b1995c10b3ef856c40 Mon Sep 17 00:00:00 2001 From: Jim Park Date: Mon, 16 Mar 2026 00:52:40 -0700 Subject: [PATCH 2/3] fix: sync package-lock.json with onnxruntime-node ^1.24.0 dependency CI was failing because package-lock.json still referenced onnxruntime-node@1.21.0 after package.json was updated to require ^1.24.0. Co-Authored-By: Claude Opus 4.6 (1M context) --- gitnexus/package-lock.json | 188 +++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 101 deletions(-) diff --git a/gitnexus/package-lock.json b/gitnexus/package-lock.json index e76b6d475..679687ade 100644 --- a/gitnexus/package-lock.json +++ b/gitnexus/package-lock.json @@ -23,6 +23,7 @@ "graphology-utils": "^2.3.0", "lru-cache": "^11.0.0", "mnemonist": "^0.39.0", + "onnxruntime-node": "^1.24.0", "pandemonium": "^2.4.0", "tree-sitter": "^0.21.0", "tree-sitter-c": "^0.21.0", @@ -35,7 +36,6 @@ "tree-sitter-python": "^0.21.0", "tree-sitter-ruby": "^0.23.1", "tree-sitter-rust": "^0.21.0", - "tree-sitter-swift": "^0.6.0", "tree-sitter-typescript": "^0.21.0", "uuid": "^13.0.0" }, @@ -606,6 +606,29 @@ "sharp": "^0.34.1" } }, + "node_modules/@huggingface/transformers/node_modules/onnxruntime-common": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0.tgz", + "integrity": "sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==", + "license": "MIT" + }, + "node_modules/@huggingface/transformers/node_modules/onnxruntime-node": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.21.0.tgz", + "integrity": "sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==", + "hasInstallScript": true, + "license": "MIT", + "os": [ + "win32", + "darwin", + "linux" + ], + "dependencies": { + "global-agent": "^3.0.0", + "onnxruntime-common": "1.21.0", + "tar": "^7.0.1" + } + }, "node_modules/@img/colour": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", @@ -1160,15 +1183,6 @@ "node-addon-api": "^6.0.0" } }, - "node_modules/@ladybugdb/core/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/@ladybugdb/core/node_modules/cmake-js": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-8.0.0.tgz", @@ -1218,40 +1232,12 @@ "node": ">=20" } }, - "node_modules/@ladybugdb/core/node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@ladybugdb/core/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/@ladybugdb/core/node_modules/tar": { - "version": "7.5.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", - "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@ladybugdb/core/node_modules/which": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", @@ -1267,15 +1253,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@ladybugdb/core/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.25.3", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz", @@ -2345,6 +2322,15 @@ "node": ">= 0.6" } }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -2524,6 +2510,15 @@ "node": ">=18" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/cli-progress": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", @@ -3838,6 +3833,18 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/mnemonist": { "version": "0.39.8", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.8.tgz", @@ -3973,15 +3980,15 @@ } }, "node_modules/onnxruntime-common": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0.tgz", - "integrity": "sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==", + "version": "1.24.3", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.24.3.tgz", + "integrity": "sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==", "license": "MIT" }, "node_modules/onnxruntime-node": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.21.0.tgz", - "integrity": "sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==", + "version": "1.24.3", + "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.24.3.tgz", + "integrity": "sha512-JH7+czbc8ALA819vlTgcV+Q214/+VjGeBHDjX81+ZCD0PCVCIFGFNtT0V4sXG/1JXypKPgScQcB3ij/hk3YnTg==", "hasInstallScript": true, "license": "MIT", "os": [ @@ -3990,55 +3997,9 @@ "linux" ], "dependencies": { + "adm-zip": "^0.5.16", "global-agent": "^3.0.0", - "onnxruntime-common": "1.21.0", - "tar": "^7.0.1" - } - }, - "node_modules/onnxruntime-node/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/onnxruntime-node/node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/onnxruntime-node/node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/onnxruntime-node/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" + "onnxruntime-common": "1.24.3" } }, "node_modules/onnxruntime-web": { @@ -4856,6 +4817,22 @@ "node": ">=8" } }, + "node_modules/tar": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", + "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -5722,6 +5699,15 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", From bf66c824cd89e4b887508f5eadb4c058353c6a65 Mon Sep 17 00:00:00 2001 From: Jim Park Date: Sat, 21 Mar 2026 17:30:23 -0700 Subject: [PATCH 3/3] fix: clarify that ORT CUDA binaries are linux/x64 only ORT 1.24.x downloads CUDA provider .so from NuGet at postinstall, but only for linux/x64. The process.arch guard correctly returns false on arm64 (safe CPU fallback), but the prior comment implied arm64 CUDA was supported. Clarify the actual state. Co-Authored-By: Claude Opus 4.6 (1M context) --- gitnexus/src/core/embeddings/embedder.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitnexus/src/core/embeddings/embedder.ts b/gitnexus/src/core/embeddings/embedder.ts index 99b7eddb6..807123b0e 100644 --- a/gitnexus/src/core/embeddings/embedder.ts +++ b/gitnexus/src/core/embeddings/embedder.ts @@ -38,7 +38,9 @@ function hasOrtCudaProvider(): boolean { const transformersDir = dirname(require.resolve('@huggingface/transformers/package.json')); const ortRequire = createRequire(join(transformersDir, 'package.json')); const ortPath = dirname(ortRequire.resolve('onnxruntime-node/package.json')); - const arch = process.arch; // x64, arm64, etc. + // ORT 1.24.x only ships CUDA binaries for linux/x64 (downloaded from NuGet + // at postinstall). arm64 will correctly return false here until ORT adds support. + const arch = process.arch; return existsSync(join(ortPath, 'bin', 'napi-v6', 'linux', arch, 'libonnxruntime_providers_cuda.so')); } catch { return false;