koala73/worldmonitor · error · SeedUnavailableError
series
Error message
${BLS_CANONICAL_KEY} series ${req.seriesId} What it means
getBlsSeries serves BLS series from a Redis seed cache. If no servable (valid-envelope) series matching req.seriesId is found in the seed, it throws SeedUnavailableError naming BLS_CANONICAL_KEY and the series — deliberately distinguishing seed-cache unavailability/corruption from errors blamed on a healthy canonical key (per #3707 context).
Solutions
- Verify the seriesId exists in the seed (inspect the Redis seed key / seed-meta)
- Run the seed worker to (re)populate BLS_CANONICAL_KEY
- Check server logs for a corrupt envelope and repair the seed entry
- Retry after seeding; if it persists, treat the seed as unavailable and surface a 503 for this series
Example fix
// before
const data = await getBlsSeries({ seriesId: 'CUUR0000SA0' }); // seed empty -> SeedUnavailableError
// after
await runBlsSeedWorker(); // repopulate BLS_CANONICAL_KEY first
const data = await getBlsSeries({ seriesId: 'CUUR0000SA0' }); Defensive patterns
Strategy: try-catch
Validate before calling
const meta = await redis.get(`seed-meta:${BLS_CANONICAL_KEY}`);
if (!meta) throw new Error('BLS seed not populated'); Type guard
const isServable = (entry) => entry != null && typeof entry === 'object' && typeof entry.seriesId === 'string' && Array.isArray(entry.observations);
Try / catch
try { return await getBlsSeries(req); } catch (e) { if (e instanceof SeedUnavailableError) { log.warn('BLS seed unavailable', { seriesId: req.seriesId }); return respond503(); } throw e; } Prevention
- Ensure the BLS seed worker runs before serving traffic
- Monitor seed-meta:<key> freshness and alert on staleness
- Validate seed envelopes at write time (isServableSeries)
- Keep a known-good series ID list in tests to detect seed drift
When it happens
Trigger: Requesting a seriesId absent from the seed cache; the seed Redis key holding a corrupt/unparseable envelope so isServableSeries fails for every entry; Redis seed never populated (worker down, seed job skipped).
Common situations: Typo'd or retired series ID; expired/evicted Redis seed data; seed-meta writer failing so the envelope is stale or malformed; fresh deployment before the first seed run.
Related errors
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/92248de8ab0a429b.
Report an issue: GitHub.
Appendix: source
Thrown at server/worldmonitor/economic/v1/get-bls-series.ts:70
): Promise<GetBlsSeriesResponse> {
if (!req.seriesId) return { series: undefined };
if (!KNOWN_SERIES_IDS.has(req.seriesId)) return { series: undefined };
const seeded = await readRequiredSeed(BLS_CANONICAL_KEY, value => {
const data = value as { series?: unknown } | null;
return Array.isArray(data?.series) ? (data.series as unknown[]) : undefined;
});
// A known series absent from — or malformed within — a valid seed is
// unavailable, not empty: the seeder refuses a partial cohort, so this only
// fires on drift between the published ids and the contract, or on a
// corrupted envelope. Name the series so the 503 log does not blame the
// healthy canonical key.
const series = seeded.find(
(entry): entry is BlsSeries => isServableSeries(entry) && entry.seriesId === req.seriesId,
);
if (!series) {
throw new SeedUnavailableError(`${BLS_CANONICAL_KEY} series ${req.seriesId}`);
}
const limit = normalizeLimit(req.limit);
const obs = series.observations;
const sliced = obs.length > limit ? obs.slice(-limit) : obs;
return { series: { ...series, observations: sliced } };
}
View on GitHub (pinned to e586b8b4b8)