Describe the issue
onnxruntime-node postinstall script (script/install-utils.js) fails on any environment where the NuGet feed (or the proxy in front of it) returns an HTTP 3xx redirect. The script treats any non-200 status as a hard failure because it uses Node's native https.get(), which does not follow redirects.
This is a regression / gap in the install script, not a network problem on our side: curl -L downloads the same URLs successfully, and the failure is entirely deterministic from the script's redirect handling.
Root cause
script/install-utils.js has two download helpers that never handle 3xx:
async function downloadFile(url, dest) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
https
.get(url, (res) => {
if (res.statusCode !== 200) { // 302 rejected as hard error
file.close();
fs.unlinkSync(dest);
reject(new Error(Failed to download from ${url}. HTTP status code = ${res.statusCode}));
return;
}
...
async function downloadJson(url) {
return new Promise((resolve, reject) => {
https
.get(url, (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
if (!statusCode) { ... }
if (statusCode >= 400 && statusCode < 500) { resolve(null); return; }
else if (statusCode !== 200) { // 302 rejected as hard error
reject(new Error(Failed to download build list. HTTP status code = ${statusCode}));
return;
}
...
Node's built-in https.get() follows no redirects by default, so any 301/302/307/308 from the feed fails the install. This is especially visible behind HTTP proxies (which commonly rewrite/redirect), but is also reproducible without a proxy against feeds that redirect.
Suggested fix
Follow redirects in both helpers (max ~5 hops, guard against redirect loops), or use fetch() (Node 18+), which follows redirects by default:
async function downloadJson(url) {
const res = await fetch(url, { redirect: 'follow' });
if (!res.ok) {
throw new Error(Failed to download build list. HTTP status code = ${res.status});
}
const contentType = res.headers.get('content-type') || '';
if (!/^application/json/.test(contentType)) {
throw new Error(unexpected content type: ${contentType});
}
return res.json();
}
async function downloadFile(url, dest) {
const res = await fetch(url, { redirect: 'follow' });
if (!res.ok) {
throw new Error(Failed to download from ${url}. HTTP status code = ${res.status});
}
const buf = Buffer.from(await res.arrayBuffer());
fs.writeFileSync(dest, buf);
}
(Keep the existing https-based approach and add manual Location-header handling if you need to stay on older Node versions.)
Urgency
No response
Target platform
OS: Linux x64 (also reproducible on macOS arm64) Node.js: v22.23.2 npm: 10.9.8 onnxruntime-node: 1.27.0 (also affected in 1.24.x range)
Build script
npm install -g gitnexus@latest
Error / output
npm error command failed
npm error command sh -c node ./script/install
npm error /.../onnxruntime-node/script/install-utils.js:57
npm error reject(new Error(Failed to download build list. HTTP status code = ${statusCode}));
npm error Error: Failed to download build list. HTTP status code = 302
Visual Studio Version
No response
GCC / Compiler Version
No response
Describe the issue
onnxruntime-node postinstall script (script/install-utils.js) fails on any environment where the NuGet feed (or the proxy in front of it) returns an HTTP 3xx redirect. The script treats any non-200 status as a hard failure because it uses Node's native https.get(), which does not follow redirects.
This is a regression / gap in the install script, not a network problem on our side: curl -L downloads the same URLs successfully, and the failure is entirely deterministic from the script's redirect handling.
Root cause
script/install-utils.js has two download helpers that never handle 3xx:
async function downloadFile(url, dest) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
https
.get(url, (res) => {
if (res.statusCode !== 200) { // 302 rejected as hard error
file.close();
fs.unlinkSync(dest);
reject(new Error(
Failed to download from ${url}. HTTP status code = ${res.statusCode}));return;
}
...
async function downloadJson(url) {
return new Promise((resolve, reject) => {
https
.get(url, (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
if (!statusCode) { ... }
if (statusCode >= 400 && statusCode < 500) { resolve(null); return; }
else if (statusCode !== 200) { // 302 rejected as hard error
reject(new Error(
Failed to download build list. HTTP status code = ${statusCode}));return;
}
...
Node's built-in https.get() follows no redirects by default, so any 301/302/307/308 from the feed fails the install. This is especially visible behind HTTP proxies (which commonly rewrite/redirect), but is also reproducible without a proxy against feeds that redirect.
Suggested fix
Follow redirects in both helpers (max ~5 hops, guard against redirect loops), or use fetch() (Node 18+), which follows redirects by default:
async function downloadJson(url) {
const res = await fetch(url, { redirect: 'follow' });
if (!res.ok) {
throw new Error(
Failed to download build list. HTTP status code = ${res.status});}
const contentType = res.headers.get('content-type') || '';
if (!/^application/json/.test(contentType)) {
throw new Error(
unexpected content type: ${contentType});}
return res.json();
}
async function downloadFile(url, dest) {
const res = await fetch(url, { redirect: 'follow' });
if (!res.ok) {
throw new Error(
Failed to download from ${url}. HTTP status code = ${res.status});}
const buf = Buffer.from(await res.arrayBuffer());
fs.writeFileSync(dest, buf);
}
(Keep the existing https-based approach and add manual Location-header handling if you need to stay on older Node versions.)
Urgency
No response
Target platform
OS: Linux x64 (also reproducible on macOS arm64) Node.js: v22.23.2 npm: 10.9.8 onnxruntime-node: 1.27.0 (also affected in 1.24.x range)
Build script
npm install -g gitnexus@latest
Error / output
npm error command failed
npm error command sh -c node ./script/install
npm error /.../onnxruntime-node/script/install-utils.js:57
npm error reject(new Error(
Failed to download build list. HTTP status code = ${statusCode}));npm error Error: Failed to download build list. HTTP status code = 302
Visual Studio Version
No response
GCC / Compiler Version
No response