decolua/9router · error · Error

[ProxyFetch] Proxy required but failed (strictProxy=true): $

Error message

[ProxyFetch] Proxy required but failed (strictProxy=true): ${proxyError.message}

What it means

In proxyAwareFetch, when the target host is MITM-intercepted and a proxy URL is configured, the fetch is attempted through the proxy dispatcher. If that proxy request throws and proxyOptions.strictProxy === true, it throws "[ProxyFetch] Proxy required but failed (strictProxy=true): <reason>" instead of silently falling back to a direct (possibly DNS-spoofed) connection. This is the MITM-bypass branch (line ~322).

Source

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

      "x-relay-path": `${parsed.pathname}${parsed.search}`,
    };
    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 });

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Verify the proxy is actually running and reachable at the configured URL (curl -x <proxyUrl> https://target).
  2. If direct connection is safe for this host, set strictProxy to false (or omit it) to allow fallback to direct/bypass.
  3. Check proxy auth credentials and protocol (http vs socks5) in the proxy URL.
  4. Inspect the embedded <reason>: ECONNREFUSED means proxy is down; 407 means auth failed.

Example fix

// before
await proxyAwareFetch(url, opts, { proxyUrl, strictProxy: true }); // proxy down
// after — allow fallback when direct access is acceptable
await proxyAwareFetch(url, opts, { proxyUrl, strictProxy: false });
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check proxy reachability before enabling strictProxy:
const ok = await fetch("https://example.com", { dispatcher: await getDispatcher(proxyUrl) }).then(r => r.ok).catch(() => false);
if (!ok && requireStrict) throw new Error("Proxy unreachable — fix proxy before calling");

Type guard

const strictOpts = (o) => ({ ...o, strictProxy: o?.strictProxy === true }); // make strict intent explicit

Try / catch

try {
  return await proxyAwareFetch(url, options, { ...proxyOptions, strictProxy: true });
} catch (e) {
  if (String(e.message).includes("strictProxy=true")) {
    // do NOT fall back silently; alert ops / switch proxy endpoint
  } else throw e;
}

Prevention

When it happens

Trigger: Target host is in the MITM-bypass list, a proxy URL is resolved (connection-level or env), and the proxied fetch rejects — proxy down, proxy auth rejected, CONNECT tunnel refused — while strictProxy is enabled.

Common situations: Corporate proxy credentials rotated or expired; local proxy (Clash/V2Ray) not running on the configured port; proxy URL scheme unsupported by the dispatcher; strictProxy=true left on after disabling the proxy client.

Related errors


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