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
- Verify the proxy is actually running and reachable at the configured URL (curl -x <proxyUrl> https://target).
- If direct connection is safe for this host, set strictProxy to false (or omit it) to allow fallback to direct/bypass.
- Check proxy auth credentials and protocol (http vs socks5) in the proxy URL.
- 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
- Health-check the proxy endpoint at startup and before long jobs.
- Only enable strictProxy when direct leakage is unacceptable; otherwise leave it off.
- Monitor the embedded cause (ECONNREFUSED, 407, TLS) to distinguish down-proxy vs auth issues.
- Keep proxy auth credentials in sync when your proxy provider rotates them.
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
- Failed to consume Codex reset credit: ${error.message}
- [ProxyFetch] Proxy failed, falling back to direct bypass: ${
- [ProxyFetch] Proxy failed, falling back to direct: ${proxyEr
- [Tunnel] direct URL not reachable yet, continuing via public
- [AutoPing] ${provider}:${conn.id}: refresh failed: ${e.messa
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/0ac87637b2ae85be.
Report an issue: GitHub.