koala73/worldmonitor · error · SeedUnavailableError
${REDIS_CACHE_KEY}
Error message
${REDIS_CACHE_KEY} What it means
SeedUnavailableError is thrown by fetchWorldBankIndicators when the World Bank API returns a non-OK HTTP status while fetching indicator records for the Redis seed. The Redis cache key is used as the error message to identify which seed dataset failed. It signals that fresh upstream data could not be obtained to populate the cache.
Solutions
- Check the World Bank API URL/indicator code is valid by curling it directly
- Retry after the transient upstream failure; the seed will repopulate on next request
- Check network egress and User-Agent requirements for api.worldbank.org
- Verify REDIS_CACHE_KEY/seed wiring so the failure surfaces for the right dataset
Example fix
// before
if (!response.ok) throw new SeedUnavailableError(REDIS_CACHE_KEY);
// after
if (!response.ok) {
logCacheSeedError(REDIS_CACHE_KEY, `worldbank status ${response.status}`);
throw new SeedUnavailableError(REDIS_CACHE_KEY);
} Defensive patterns
Strategy: retry
Validate before calling
const url = `https://api.worldbank.org/v2/country/${countries}/indicator/${indicator}?format=json&per_page=${perPage}`;
const probe = await fetch(url, { method: 'HEAD' });
if (!probe.ok) throw new Error(`worldbank unavailable: ${probe.status}`); Try / catch
try {
const res = await api.listWorldBankIndicators(req);
} catch (e) {
if (isSeedUnavailableError(e)) {
// backoff and retry; seed repopulates on recovery
await sleep(RETRY_DELAY_MS);
return retryOrServeStale();
}
throw e;
} Prevention
- Pre-validate indicator codes against the World Bank indicator list
- Add jittered backoff retry for upstream fetches
- Monitor World Bank API status before running seed jobs
- Keep a stale-cache fallback for seed failures
When it happens
Trigger: The World Bank API (api.worldbank.org) returns 4xx/5xx for the given indicator/country/date URL, e.g. an invalid indicator code, rate limiting, or upstream outage, during the seed fetch inside cachedFetchJsonWithMeta's refresh callback.
Common situations: World Bank API rate limiting after bursts of requests; a renamed or removed indicator code; network egress blocked from the edge/worker; transient World Bank maintenance returning 5xx.
Related errors
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/ee7719a629c59603.
Report an issue: GitHub.
Appendix: source
Thrown at server/worldmonitor/economic/v1/list-world-bank-indicators.ts:71
indicator: string,
countryList: string,
years: number,
currentYear: number,
): Promise<WorldBankCountryData[]> {
try {
const startYear = currentYear - years;
const wbUrl = `https://api.worldbank.org/v2/country/${encodeURIComponent(countryList)}/indicator/${encodeURIComponent(indicator)}?format=json&date=${startYear}:${currentYear}&per_page=1000`;
const response = await fetch(wbUrl, {
headers: {
Accept: 'application/json',
'User-Agent': CHROME_UA,
},
signal: AbortSignal.timeout(15000),
});
if (!response.ok) throw new SeedUnavailableError(REDIS_CACHE_KEY);
const data = await response.json();
if (!Array.isArray(data) || data.length < 2) throw new SeedUnavailableError(REDIS_CACHE_KEY);
if (data[1] === null && (data[0]?.total === 0 || data[0]?.total === '0')) return [];
if (!Array.isArray(data[1])) throw new SeedUnavailableError(REDIS_CACHE_KEY);
const records: any[] = data[1];
const indicatorName = records[0]?.indicator?.value || indicator;
return records
.filter((r: any) => r.countryiso3code && r.value !== null)
.map((r: any): WorldBankCountryData => ({
countryCode: r.countryiso3code || r.country?.id || '',
countryName: r.country?.value || '',
indicatorCode: indicator,
indicatorName,
year: parseInt(r.date, 10) || 0,
value: r.value,View on GitHub (pinned to e586b8b4b8)