koala73/worldmonitor · error · RssProxyPolicyError
Too many redirects
Error message
Too many redirects
What it means
fetchDirect follows at most MAX_DIRECT_REDIRECTS = 3 manual hops (301/302/303/307/308). When the fourth hop is still a redirect, the proxy gives up with this RssProxyPolicyError and HTTP 502. The bound exists to keep redirect loops from burning the Edge function invocation.
Solutions
- Count the hops: curl -sIL -o /dev/null -w '%{num_redirects}\n' '<feed-url>'
- Request the final destination URL directly through the proxy
- Fix the origin's redirect loop — alternating apex/www rewrite rules are the usual cause
- Only if chains are legitimately longer, raise MAX_DIRECT_REDIRECTS in api/rss-proxy.js and re-check the Edge timeout budget
Example fix
# before — chain longer than 3 hops
$ curl -sIL -o /dev/null -w '%{num_redirects}\n' 'https://old.example.com/rss'
5 # proxy answers 502 Too many redirects
# after — call the proxy with the resolved final URL
GET /api/rss-proxy?url=https://final.example.com/rss Defensive patterns
Strategy: validation
Validate before calling
// Count hops before handing the URL to the proxy (limit is 3)
async function hopCount(url) {
let n = 0, current = new URL(url);
for (;;) {
const res = await fetch(current, { redirect: 'manual' });
const loc = res.headers.get('location');
if (!loc || ![301,302,303,307,308].includes(res.status)) return { hops: n, finalUrl: current.href };
n += 1; current = new URL(loc, current);
if (n > 3) return { hops: n, finalUrl: current.href };
}
} Try / catch
try { await fetchFeedViaProxy(feedUrl); }
catch (err) {
if (/Too many redirects/.test(err.message)) {
const { finalUrl } = await hopCount(feedUrl);
return fetchFeedViaProxy(finalUrl); // retry once with the resolved destination
}
throw err;
} Prevention
- Canonicalize feed URLs to their final destination at config time
- Alert when a feed's hop count grows — it often precedes a loop or a wall
- Do not raise MAX_DIRECT_REDIRECTS to paper over origin redirect loops; fix the origin
When it happens
Trigger: A↔B redirect loops on the origin (typically alternating apex/www rewrite rules); cookie/consent walls that redirect forever because the proxy sends no cookies; legitimate chains longer than three hops (http→https→apex→www→feed).
Common situations: Publisher consent-redirect walls; misconfigured origin rewrites; chains that quietly grew one hop when a new canonical domain was introduced.
Related errors
- Redirect to disallowed domain
- URL protocol not allowed
- Airport delay filters are not supported
- Airport delay page_size must be 0
- body-too-large
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-08-21).
Data as JSON: /api/errors/dcc91d8c0cf296a7.
Report an issue: GitHub.
Appendix: source
Thrown at api/rss-proxy.js:321
let currentUrl = parsedUrl;
for (let redirectCount = 0; redirectCount <= MAX_DIRECT_REDIRECTS; redirectCount += 1) {
const response = await fetchRssResponse(currentUrl.href, {
headers: rssFetchHeadersForHost(currentUrl.hostname),
redirect: 'manual',
}, timeout);
if (!DIRECT_REDIRECT_STATUSES.has(response.status)) {
return response;
}
const location = response.headers.get('location');
if (!location) {
return response;
}
if (redirectCount === MAX_DIRECT_REDIRECTS) {
throw new RssProxyPolicyError('Too many redirects', 502);
}
const redirectUrl = new URL(location, currentUrl.href);
assertAllowedRedirect(redirectUrl);
currentUrl = redirectUrl;
}
};
let response;
let usedRelay = false;
if (isRelayOnly) {
// Skip direct fetch entirely — these domains block Vercel IPs
response = await fetchViaRailway(feedUrl, timeout);
usedRelay = !!response;
if (!response) throw new Error(`Railway relay unavailable for relay-only domain: ${hostname}`);
} else {
try {View on GitHub (pinned to e586b8b4b8)