somratpro Claude Opus 4.7 commited on
Commit
87bcb42
·
1 Parent(s): f83188b

Fix UND_ERR_INVALID_ARG by not spreading init into proxy fetch

Browse files

Root 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>

Files changed (2) hide show
  1. cloudflare-proxy.js +44 -14
  2. workspace-sync.py +5 -0
cloudflare-proxy.js CHANGED
@@ -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(originalFetch(String(proxiedUrl), fetchOpts));
 
 
 
207
  }
208
 
 
 
 
 
209
  const newInit = {
210
- ...init,
211
  headers: mergedHeaders,
212
  };
213
- if (newInit.body instanceof ReadableStream && !newInit.duplex) {
214
- newInit.duplex = "half";
 
 
 
215
  }
216
-
217
- return logProxyError(originalFetch(String(proxiedUrl), newInit));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  };
219
  }
220
 
@@ -320,9 +347,12 @@ if (PROXY_URL) {
320
  return exports;
321
  };
322
 
323
- if (DEBUG) {
324
- log(`[cloudflare-proxy] Transparent proxy active in ${PROXY_ALL ? "wildcard" : "list"} mode`);
325
- log(`[cloudflare-proxy] Target proxy: ${proxy.hostname}`);
 
 
 
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}`);
workspace-sync.py CHANGED
@@ -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