koala73/worldmonitor · error · Error
Railway relay unavailable for relay-only domain: ${hostname}
Error message
Railway relay unavailable for relay-only domain: ${hostname} What it means
Thrown by the RSS proxy when a relay-only domain (listed in RELAY_ONLY_DOMAINS — domains known to block Vercel edge IPs) is requested but fetchViaRailway() returned a falsy value. fetchViaRailway returns null when getRelayBaseUrl() is empty (the Railway relay URL environment variable is not configured), meaning the relay path is entirely unavailable. For relay-only domains, direct fetch is skipped, so this is a total failure — there is no fallback path.
Source
Thrown at api/rss-proxy.js:185
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 {
response = await fetchDirect();
} catch (directError) {
if (directError instanceof RssProxyPolicyError) throw directError;
// A throwing relay leg here must not replace directError — a null or
// non-ok relay response already falls through to it below, so a thrown
// relay error should too, rather than becoming the reported failure.
let relayResponse = null;
try {
relayResponse = await fetchViaRailway(feedUrl, timeout);
} catch (relayError) {
console.error('RSS proxy relay fallback error:', feedUrl, relayError instanceof Error ? relayError.message : String(relayError));
}
response = relayResponse;
usedRelay = !!response;
if (!response) throw directError;
}View on GitHub (pinned to ffec79ac33)
Solutions
- Verify the Railway relay URL environment variable is set in the Vercel edge function configuration (check getRelayBaseUrl and the env var it reads).
- Confirm the Railway relay service is running and responding at the configured URL.
- If the relay is temporarily down, the feed cannot be fetched — this is expected for relay-only domains. Wait for relay recovery.
- If this is a new relay-only domain addition, ensure the Railway relay service can actually reach it before adding to RELAY_ONLY_DOMAINS.
Defensive patterns
Strategy: fallback
Validate before calling
// Check relay configuration before requesting a relay-only feed
const RELAY_ONLY_DOMAINS = ['rss.cnn.com','www.defensenews.com','layoffs.fyi','news.un.org','www.cisa.gov','www.iaea.org','www.who.int','www.crisisgroup.org','english.alarabiya.net','www.timesofisrael.com','www.scmp.com','kyivindependent.com','www.themoscowtimes.com','feeds.24.com','feeds.capi24.com','islandtimes.org','www.atlanticcouncil.com'];
const isRelayOnly = RELAY_ONLY_DOMAINS.includes(new URL(feedUrl).hostname);
if (isRelayOnly) {
const health = await fetch('/api/health').then(r => r.json());
if (!health.relayReachable) {
throw new Error('Railway relay is down; relay-only feeds unavailable until recovery');
}
} Type guard
function isRailwayRelayUnavailableError(e: unknown): boolean {
return e instanceof Error && e.message.startsWith('Railway relay unavailable for relay-only domain');
} Try / catch
try {
const feed = await fetch('/api/rss-proxy?url=' + encodeURIComponent(feedUrl));
} catch (e) {
if (isRailwayRelayUnavailableError(e)) {
// No fallback for relay-only domains — the relay is the only path
// Retry after confirming relay recovery, or skip this feed
logRelayOutage(e.message);
} else throw e;
} Prevention
- Monitor the Railway relay service health independently — relay-only domains have no direct-fetch fallback.
- Ensure the relay URL env var is set in all edge function environments (preview, production).
- Do not add a domain to RELAY_ONLY_DOMAINS unless the Railway relay can actually reach it.
When it happens
Trigger: Requesting a feed from a relay-only domain (e.g. rss.cnn.com, www.scmp.com, kyivindependent.com) when the Railway relay service URL is not set in the edge function's environment — getRelayBaseUrl() returns null, fetchViaRailway returns null, and since direct fetch is skipped for relay-only domains, there is no other path. This is a configuration/infrastructure outage, not a transient network issue.
Common situations: The RELAY_BASE_URL (or equivalent) env var is missing from the Vercel edge function environment after a deploy; the Railway relay service is down and its URL was removed/emptied; a new relay-only domain was added to the set but the relay service was not deployed; env var naming drift between local and deployed environments.
Related errors
- URL protocol not allowed
- Redirect to disallowed domain
- Too many redirects
- Redis not configured
- payload_too_large
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/9cf9daaea48fdd42.
Report an issue: GitHub.