Spaces:
Running
Fix UND_ERR_INVALID_ARG by not spreading init into proxy fetch
Browse filesRoot cause: spreading `init` into the new fetch options carried over
`dispatcher`/`client` references that undici had pinned to the original
target host's connection pool. When we changed the URL to the CF Worker
but kept the original dispatcher, undici threw UND_ERR_INVALID_ARG
synchronously (~4ms, not a network error).
- cloudflare-proxy.js: build newInit explicitly with only well-known
fetch options (method, headers, body, signal, redirect, etc.) instead
of `...init`. Drop dispatcher/client/duplex from caller's init unless
body is a ReadableStream. Add init debug info to error log.
- cloudflare-proxy.js: dedupe startup banner across child Node procs
(NODE_OPTIONS=--require makes script run in every spawn).
- cloudflare-proxy.js: drop redundant "Host match" log (covered by
"Redirecting").
- workspace-sync.py: silence huggingface_hub WARNING-level chatter
("No files have been modified...") via logging config.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- cloudflare-proxy.js +44 -14
- workspace-sync.py +5 -0
|
@@ -56,10 +56,6 @@ if (PROXY_URL) {
|
|
| 56 |
normalized === domain || normalized.endsWith(`.${domain}`),
|
| 57 |
);
|
| 58 |
|
| 59 |
-
if (DEBUG && should && normalized !== proxy.hostname) {
|
| 60 |
-
log(`[cloudflare-proxy] Host match: ${normalized}`);
|
| 61 |
-
}
|
| 62 |
-
|
| 63 |
return should;
|
| 64 |
};
|
| 65 |
|
|
@@ -176,7 +172,7 @@ if (PROXY_URL) {
|
|
| 176 |
|
| 177 |
const proxiedUrl = new URL(url.pathname + url.search, proxy);
|
| 178 |
|
| 179 |
-
const logProxyError = (promise) => {
|
| 180 |
promise
|
| 181 |
.then(r => {
|
| 182 |
if (DEBUG && !r.ok) {
|
|
@@ -189,6 +185,9 @@ if (PROXY_URL) {
|
|
| 189 |
? ` | cause: ${cause?.code || cause?.message || String(cause)}`
|
| 190 |
: "";
|
| 191 |
log(`[cloudflare-proxy] Proxy FAILED ${hostname}: ${err?.message}${causeStr}`);
|
|
|
|
|
|
|
|
|
|
| 192 |
});
|
| 193 |
return promise;
|
| 194 |
};
|
|
@@ -203,18 +202,46 @@ if (PROXY_URL) {
|
|
| 203 |
fetchOpts.body = request.body;
|
| 204 |
fetchOpts.duplex = "half";
|
| 205 |
}
|
| 206 |
-
return logProxyError(
|
|
|
|
|
|
|
|
|
|
| 207 |
}
|
| 208 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
const newInit = {
|
| 210 |
-
|
| 211 |
headers: mergedHeaders,
|
| 212 |
};
|
| 213 |
-
if (
|
| 214 |
-
newInit.
|
|
|
|
|
|
|
|
|
|
| 215 |
}
|
| 216 |
-
|
| 217 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
};
|
| 219 |
}
|
| 220 |
|
|
@@ -320,9 +347,12 @@ if (PROXY_URL) {
|
|
| 320 |
return exports;
|
| 321 |
};
|
| 322 |
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
|
|
|
|
|
|
|
|
|
| 326 |
}
|
| 327 |
} catch (error) {
|
| 328 |
log(`[cloudflare-proxy] Failed to initialize: ${error.message}`);
|
|
|
|
| 56 |
normalized === domain || normalized.endsWith(`.${domain}`),
|
| 57 |
);
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
return should;
|
| 60 |
};
|
| 61 |
|
|
|
|
| 172 |
|
| 173 |
const proxiedUrl = new URL(url.pathname + url.search, proxy);
|
| 174 |
|
| 175 |
+
const logProxyError = (promise, debugInfo) => {
|
| 176 |
promise
|
| 177 |
.then(r => {
|
| 178 |
if (DEBUG && !r.ok) {
|
|
|
|
| 185 |
? ` | cause: ${cause?.code || cause?.message || String(cause)}`
|
| 186 |
: "";
|
| 187 |
log(`[cloudflare-proxy] Proxy FAILED ${hostname}: ${err?.message}${causeStr}`);
|
| 188 |
+
if (DEBUG && debugInfo) {
|
| 189 |
+
log(`[cloudflare-proxy] Debug: ${debugInfo}`);
|
| 190 |
+
}
|
| 191 |
});
|
| 192 |
return promise;
|
| 193 |
};
|
|
|
|
| 202 |
fetchOpts.body = request.body;
|
| 203 |
fetchOpts.duplex = "half";
|
| 204 |
}
|
| 205 |
+
return logProxyError(
|
| 206 |
+
originalFetch(String(proxiedUrl), fetchOpts),
|
| 207 |
+
`request-mode method=${request.method} hasBody=${!!request.body}`,
|
| 208 |
+
);
|
| 209 |
}
|
| 210 |
|
| 211 |
+
// Build a fresh init: do NOT spread `init` because it may carry a
|
| 212 |
+
// `dispatcher`/`client` pinned to the original target's connection
|
| 213 |
+
// pool, which causes undici to throw UND_ERR_INVALID_ARG when we
|
| 214 |
+
// change the origin. Forward only well-known fetch options.
|
| 215 |
const newInit = {
|
| 216 |
+
method: init?.method || "GET",
|
| 217 |
headers: mergedHeaders,
|
| 218 |
};
|
| 219 |
+
if (init?.body != null) {
|
| 220 |
+
newInit.body = init.body;
|
| 221 |
+
if (init.body instanceof ReadableStream) {
|
| 222 |
+
newInit.duplex = init.duplex || "half";
|
| 223 |
+
}
|
| 224 |
}
|
| 225 |
+
if (init?.signal) newInit.signal = init.signal;
|
| 226 |
+
if (init?.redirect) newInit.redirect = init.redirect;
|
| 227 |
+
if (init?.credentials) newInit.credentials = init.credentials;
|
| 228 |
+
if (init?.cache) newInit.cache = init.cache;
|
| 229 |
+
if (init?.mode) newInit.mode = init.mode;
|
| 230 |
+
if (init?.referrer) newInit.referrer = init.referrer;
|
| 231 |
+
if (init?.referrerPolicy) newInit.referrerPolicy = init.referrerPolicy;
|
| 232 |
+
if (init?.integrity) newInit.integrity = init.integrity;
|
| 233 |
+
if (init?.keepalive != null) newInit.keepalive = init.keepalive;
|
| 234 |
+
|
| 235 |
+
const bodyType = init?.body == null
|
| 236 |
+
? "none"
|
| 237 |
+
: init.body instanceof ReadableStream
|
| 238 |
+
? "ReadableStream"
|
| 239 |
+
: (init.body?.constructor?.name || typeof init.body);
|
| 240 |
+
|
| 241 |
+
return logProxyError(
|
| 242 |
+
originalFetch(String(proxiedUrl), newInit),
|
| 243 |
+
`init-mode method=${newInit.method} body=${bodyType} initKeys=${Object.keys(init || {}).join(",")}`,
|
| 244 |
+
);
|
| 245 |
};
|
| 246 |
}
|
| 247 |
|
|
|
|
| 347 |
return exports;
|
| 348 |
};
|
| 349 |
|
| 350 |
+
// Startup banner: only print once for the parent process to avoid the
|
| 351 |
+
// "active in list mode" banner repeating for every child Node spawn
|
| 352 |
+
// (NODE_OPTIONS=--require makes this script run in every Node process).
|
| 353 |
+
if (DEBUG && !process.env.__CF_PROXY_BANNER_SHOWN) {
|
| 354 |
+
process.env.__CF_PROXY_BANNER_SHOWN = "1";
|
| 355 |
+
log(`[cloudflare-proxy] active (${PROXY_ALL ? "wildcard" : "list"}) -> ${proxy.hostname}`);
|
| 356 |
}
|
| 357 |
} catch (error) {
|
| 358 |
log(`[cloudflare-proxy] Failed to initialize: ${error.message}`);
|
|
@@ -9,6 +9,7 @@ remotes or requiring a manual HF_USERNAME secret.
|
|
| 9 |
|
| 10 |
import hashlib
|
| 11 |
import json
|
|
|
|
| 12 |
import os
|
| 13 |
import shutil
|
| 14 |
import signal
|
|
@@ -20,6 +21,10 @@ from pathlib import Path
|
|
| 20 |
|
| 21 |
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
from huggingface_hub import HfApi, snapshot_download, upload_folder
|
| 24 |
from huggingface_hub.errors import HfHubHTTPError, RepositoryNotFoundError
|
| 25 |
|
|
|
|
| 9 |
|
| 10 |
import hashlib
|
| 11 |
import json
|
| 12 |
+
import logging
|
| 13 |
import os
|
| 14 |
import shutil
|
| 15 |
import signal
|
|
|
|
| 21 |
|
| 22 |
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
| 23 |
|
| 24 |
+
# Silence huggingface_hub's chatty per-file "No files have been modified..."
|
| 25 |
+
# logs from upload_large_folder. Keep warnings/errors visible.
|
| 26 |
+
logging.getLogger("huggingface_hub").setLevel(logging.WARNING)
|
| 27 |
+
|
| 28 |
from huggingface_hub import HfApi, snapshot_download, upload_folder
|
| 29 |
from huggingface_hub.errors import HfHubHTTPError, RepositoryNotFoundError
|
| 30 |
|