decolua/9router · warning

[ProxyFetch] Proxy failed, falling back to direct bypass: ${

Error message

[ProxyFetch] Proxy failed, falling back to direct bypass: ${proxyError.message}

What it means

When a proxy is configured for a request, proxyAwareFetch attempts the fetch through the proxy dispatcher (undici ProxyAgent). If the proxied attempt throws and strictProxy is not enabled, it logs this warning and retries directly, resolving the real IP via DNS to bypass potential DNS spoofing. Only when strictProxy=true does the proxy failure propagate as a thrown error.

Source

Thrown at open-sse/utils/proxyFetch.js:324

    return originalFetch(vercelRelayUrl, { ...options, headers: relayHeaders });
  }

  const connectionProxyUrl = resolveConnectionProxyUrl(targetUrl, proxyOptions);
  const envProxyUrl = connectionProxyUrl ? null : normalizeProxyUrl(getEnvProxyUrl(targetUrl));
  const proxyUrl = connectionProxyUrl || envProxyUrl;

  // MITM DNS bypass: for known MITM-intercepted hosts, resolve real IP to avoid DNS spoof
  if (shouldBypassMitmDns(targetUrl)) {
    if (proxyUrl) {
      // Proxy resolves DNS externally (not affected by /etc/hosts) — use proxy directly
      try {
        const dispatcher = await getDispatcher(proxyUrl);
        return await originalFetch(url, { ...options, dispatcher });
      } catch (proxyError) {
        if (proxyOptions?.strictProxy === true) {
          throw new Error(`[ProxyFetch] Proxy required but failed (strictProxy=true): ${proxyError.message}`);
        }
        console.warn(`[ProxyFetch] Proxy failed, falling back to direct bypass: ${proxyError.message}`);
      }
    }
    // No proxy — manually resolve real IP to bypass DNS spoof
    try {
      const parsedUrl = new URL(targetUrl);
      const realIP = await resolveRealIP(parsedUrl.hostname);
      if (realIP) return await createBypassRequest(parsedUrl, realIP, options);
    } catch (error) {
      console.warn(`[ProxyFetch] MITM bypass failed: ${error.message}`);
    }
  }

  if (proxyUrl) {
    try {
      const dispatcher = await getDispatcher(proxyUrl);
      return await originalFetch(url, { ...options, dispatcher });
    } catch (proxyError) {
      // If strictProxy is enabled, fail hard instead of falling back to direct

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Verify the proxy URL (protocol, host, port, credentials) in proxy settings and test it with curl
  2. If traffic MUST go through the proxy, set strictProxy=true so failures throw instead of leaking direct requests
  3. Check that the proxy is running and reachable from the gateway host
  4. Confirm proxy auth credentials are included in the proxy URL (http://user:pass@host:port)
  5. If direct fallback is acceptable, treat this warning as informational and fix the proxy at leisure

Example fix

// before: silent direct fallback on proxy failure
proxyOptions: { proxyUrl: "http://127.0.0.1:9999" }
// after: hard-fail when the proxy is required
proxyOptions: { proxyUrl: "http://127.0.0.1:9999", strictProxy: true }
Defensive patterns

Strategy: try-catch

Validate before calling

const u = new URL(proxyUrl);
if (!/^https?:$/.test(u.protocol)) throw new Error('proxy must be http(s)');
await fetch('http://' + u.host + '/', { signal: AbortSignal.timeout(3000) }); // proxy reachable?

Type guard

const isProxyFailure = (e) => e instanceof Error && /Proxy required but failed|proxy/i.test(e.message);

Try / catch

try {
  return await proxyAwareFetch(url, { proxyOptions });
} catch (e) {
  if (isProxyFailure(e)) {
    // strictProxy threw — proxy is mandatory in this environment
    console.error('proxy mandatory but down:', e.message);
  }
  throw e;
}

Prevention

When it happens

Trigger: The proxied fetch threw — proxy host unreachable/wrong port, proxy auth rejected (407), proxy timeout, TLS failure through the proxy, or getDispatcher failed to build an agent for the proxy URL.

Common situations: Proxy server down or the wrong address/port in proxy config; corporate proxy requires credentials not supplied; SOCKS vs HTTP proxy type mismatch; firewall blocks the proxy port; proxy certificate issues.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/d9c184a78cfc98a6. Report an issue: GitHub.