koala73/worldmonitor · warning · Error
relay returned ${resp.status}
Error message
relay returned ${resp.status} What it means
Inside the cachedFetchJson producer of searchGoogleDates, a non-OK response from the relay service (/google-flights/search-dates, 30s timeout) throws this Error. The handler's outer catch converts it into a degraded response {dates: [], degraded: true, error: 'relay returned <status>'}, so the RPC client sees HTTP 200 with degraded=true rather than a thrown error; failed fetches are not cached.
Source
Thrown at server/worldmonitor/aviation/v1/search-google-dates.ts:62
sort_by_price: String(req.sortByPrice ?? false),
passengers: String(passengers),
});
for (const airline of airlines) {
params.append('airlines', airline);
}
const cacheKey = `aviation:gf-dates:${origin}:${destination}:${startDate}:${endDate}:${params.toString()}:v1`;
try {
const data = await cachedFetchJson<{ dates: unknown[]; partial?: boolean }>(
cacheKey,
CACHE_TTL,
async () => {
const resp = await fetch(`${relayBaseUrl}/google-flights/search-dates?${params}`, {
headers: getRelayHeaders(),
signal: AbortSignal.timeout(30_000),
});
if (!resp.ok) throw new Error(`relay returned ${resp.status}`);
const json = (await resp.json()) as { dates?: unknown[]; partial?: boolean; error?: string };
if (!Array.isArray(json.dates)) throw new Error(json.error ?? 'no results');
return { dates: json.dates, partial: json.partial };
},
);
if (!data) {
return { dates: [], degraded: true, error: 'no results' };
}
return {
dates: data.dates as SearchGoogleDatesResponse['dates'],
degraded: data.partial === true,
error: data.partial === true ? 'partial results: one or more date chunks failed' : '',
};
} catch (err) {
return { dates: [], degraded: true, error: err instanceof Error ? err.message : 'search failed' };
}View on GitHub (pinned to 9361220cc0)
Solutions
- Check the response's degraded/error fields — do not treat an empty dates array as 'no flights'
- Verify the relay env config (base URL and shared headers via getRelayBaseUrl()/getRelayHeaders) matches the deployed relay
- Inspect relay service logs for the matching status code (401 → secret mismatch, 429 → throttling, 5xx → relay health)
- Retry after a backoff window; nothing is cached on failure so a later attempt re-hits the relay
Example fix
// before — empty array read as 'no flights on those dates'
const { dates } = await client.searchGoogleDates(req);
if (dates.length === 0) showNoFlights();
// after — degraded flag distinguishes upstream failure from a true empty result
const res = await client.searchGoogleDates(req);
if (res.degraded) showRetryableError(res.error); // 'relay returned 502'
else if (res.dates.length === 0) showNoFlights(); Defensive patterns
Strategy: fallback
Type guard
interface DatesResult { dates: unknown[]; degraded: boolean; error: string }
function isDegradedDates(r: DatesResult): boolean {
return r.degraded === true;
} Try / catch
// No throw escapes this handler — it converts relay failures to degraded responses.
const res = await searchGoogleDates(req);
if (res.degraded) {
if (res.error.startsWith('relay returned')) return retryLater(res.error); // upstream status embedded
return showEmptyState(res.error);
} Prevention
- Always branch on the degraded flag before interpreting dates.length
- Keep relay credentials (RELAY_* env) in the same rotation pipeline as other upstream secrets
- Retry degraded relay responses with backoff — failures are not cached, so the next call re-hits the relay
When it happens
Trigger: Relay VM restarting or down (502/503); relay rejects the auth headers from getRelayHeaders() (401/403 — stale relay secret); relay rate-limits or blocks the request (429); Cloudflare/WAF in front of the relay rejecting the user-agent.
Common situations: Relay secret rotated but the server env (RELAY_* variables consumed by _shared/relay.ts) not updated; relay host under load during fare-search bursts; relay deployment mid-restart; network path between the Edge runtime and the relay failing.
Related errors
- relay returned ${resp.status}
- no results
- no results
- DNS ${recordType} lookup failed: HTTP ${response.status}
- callbackUrl DNS resolution failed: ${message}
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-08-21).
Data as JSON: /api/errors/f261d4384c2c256a.
Report an issue: GitHub.