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

  1. Verify the Railway relay URL environment variable is set in the Vercel edge function configuration (check getRelayBaseUrl and the env var it reads).
  2. Confirm the Railway relay service is running and responding at the configured URL.
  3. If the relay is temporarily down, the feed cannot be fetched — this is expected for relay-only domains. Wait for relay recovery.
  4. 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

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


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/9cf9daaea48fdd42. Report an issue: GitHub.