koala73/worldmonitor · error · SeedUnavailableError
${cacheKey}
Error message
${cacheKey} What it means
SeedUnavailableError thrown by listWorldBankIndicators when the cachedFetchJsonWithMeta result is missing or its data.data field is not an array — i.e. the refresh callback returned an unexpected shape. The specific cacheKey (including indicator, countries, years, current year) is in the message.
Solutions
- Inspect the cacheKey in the message and check Redis for the stale/missing entry
- Verify fetchWorldBankIndicators still returns { data: [...] } matching ListWorldBankIndicatorsResponse
- Check recent refactors to either function for shape changes
- Retry after upstream recovery and confirm the seed repopulates
Defensive patterns
Strategy: type-guard
Validate before calling
if (!result?.data || !Array.isArray(result.data.data)) {
throw new Error(`bad cached shape for ${cacheKey}`);
} Type guard
function isValidIndicatorResponse(v: unknown): v is ListWorldBankIndicatorsResponse {
return !!v && typeof v === 'object' && Array.isArray((v as any).data);
} Try / catch
try {
const res = await api.listWorldBankIndicators(req);
if (!isValidIndicatorResponse(res)) throw new Error('shape');
return res;
} catch {
return { data: [], pagination: undefined };
} Prevention
- Type-check the refresh callback's return against the response type
- Add a contract test for fetchWorldBankIndicators' shape
- Version cached payloads so old shapes are invalidated
- Check Redis entry for the specific cacheKey when this fires
When it happens
Trigger: fetchWorldBankIndicators resolves but returns a value without a valid data array, or cachedFetchJsonWithMeta returns a stale/failed result the code treats as invalid; typically follows an upstream World Bank problem.
Common situations: World Bank API outage during cache refresh; a refactor changing the response shape of fetchWorldBankIndicators without updating this check; cache read returning a value typed differently than expected.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- series
- cache_all_null
- cache_all_null
- Crypto gap cache unavailable
- Failed to persist resilience score generation for
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/87fcffe49cb1f62c.
Report an issue: GitHub.
Appendix: source
Thrown at server/worldmonitor/economic/v1/list-world-bank-indicators.ts:116
req: ListWorldBankIndicatorsRequest,
): Promise<ListWorldBankIndicatorsResponse> {
try {
// The exported client accepts generic indicator codes, not just the tech
// display catalogue. Bound their grammar without restricting that contract.
if (req.indicatorCode.length > 64 || !/^[A-Z0-9_]+(?:\.[A-Z0-9_]+)+$/.test(req.indicatorCode)) {
return { data: [], pagination: undefined };
}
const country = normalizeCountries(req.countryCode);
if (country === null || !Number.isInteger(req.year)) return { data: [], pagination: undefined };
// Match the existing World Bank relay's maximum lookback.
const years = req.year > 0 ? Math.min(req.year, 30) : 5;
const currentYear = new Date().getFullYear();
const cacheKey = `${REDIS_CACHE_KEY}:${req.indicatorCode}:${country || '__default__'}:${years}:${currentYear}`;
const result = await cachedFetchJsonWithMeta<ListWorldBankIndicatorsResponse>(cacheKey, REDIS_CACHE_TTL, async () => {
const data = await fetchWorldBankIndicators(req.indicatorCode, country || TECH_COUNTRIES.join(';'), years, currentYear);
return { data, pagination: undefined };
}, 120, { cacheFailures: false });
if (!result.data || !Array.isArray(result.data.data)) throw new SeedUnavailableError(cacheKey);
return result.data;
} catch {
throw new SeedUnavailableError(REDIS_CACHE_KEY);
}
}
View on GitHub (pinned to e586b8b4b8)