koala73/worldmonitor · error · SeedUnavailableError
${key}
Error message
${key} What it means
readRequiredSeed reads a seed dataset from the shared Redis-backed JSON cache via readCachedJson(key, true). A seed marked 'required' must be a cache hit AND must decode successfully; otherwise it throws SeedUnavailableError carrying the seed key as its message, signaling the caller (e.g. getHumanitarianSummary) cannot serve data without this pre-seeded dataset.
Solutions
- Run/restart the seed worker (or api/bootstrap.js wiring) so the seed for this key is (re)written to Redis; verify seed-meta:<key> exists.
- Check Redis credentials and reachability — a cache read error is logged for this key before the throw.
- Inspect the cached value with the same key in Redis and fix the decode function if the stored shape drifted.
- Wrap the caller to serve a fallback/degraded response when SeedUnavailableError is thrown.
Example fix
// before
const summary = await getHumanitarianSummary(iso3);
// after
let summary;
try {
summary = await getHumanitarianSummary(iso3);
} catch (err) {
if (err instanceof SeedUnavailableError) {
return { summary: null, unavailable: true, seed: err.message };
}
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
import { exists } from './seed-check';
// before calling, ensure the seed metadata exists
const seeded = await seedMetaExists(`seed-meta:${key}`); // returns boolean
if (!seeded) {
console.warn(`Seed ${key} not present; run the seed worker first.`);
} Type guard
function isSeedUnavailableError(err: unknown): err is SeedUnavailableError {
return err instanceof SeedUnavailableError;
} Try / catch
try {
const data = await readRequiredSeed(key, decode);
} catch (err) {
if (isSeedUnavailableError(err)) {
console.error(`Required seed missing or undecodable: ${err.message}`);
return fallbackData;
}
throw err;
} Prevention
- Run api/bootstrap.js / seed workers before starting readers so all required keys are populated.
- Verify seed-meta:<key> exists in Redis as the seed health marker.
- Alert on logCacheReadError entries — they precede this throw when Redis is failing.
- Bump/refresh seeds after decoder schema changes to avoid decode() returning undefined on stale JSON.
When it happens
Trigger: Requesting a dependent endpoint (e.g. humanitarian summary) when the Redis seed for the key was never written, expired, or evicted; readCachedJson returns status 'miss' or 'error' (Redis down/misconfigured); the cached JSON exists but decode() returns undefined because the stored shape no longer matches the decoder.
Common situations: Fresh environment where seed scripts were never run or UPSTASH credentials are missing; seed TTL expired and the seed worker hasn't refreshed; schema drift after a deploy changed the decoder while old cached JSON remains; Redis outage logged via logCacheReadError before the throw.
Related errors
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/760ba613d755eb6e.
Report an issue: GitHub.
Appendix: source
Thrown at server/_shared/required-seed.ts:18
import { logCacheReadError, readCachedJson } from './redis';
export class SeedUnavailableError extends Error {
readonly statusCode = 503;
constructor(key: string) {
super(`Seed unavailable: ${key}`);
this.name = 'SeedUnavailableError';
}
}
export async function readRequiredSeed<T>(
key: string,
decode: (value: unknown) => T | undefined,
): Promise<T> {
const result = await readCachedJson(key, true);
if (result.status === 'error') logCacheReadError(key, result.error);
if (result.status !== 'hit') throw new SeedUnavailableError(key);
const data = decode(result.value);
if (data === undefined) throw new SeedUnavailableError(key);
return data;
}
View on GitHub (pinned to e586b8b4b8)