{"record":{"id":"760ba613d755eb6e","repo":"koala73/worldmonitor","slug":"key","errorCode":null,"errorMessage":"${key}","messagePattern":"\\$\\{key\\}","errorType":"exception","errorClass":"SeedUnavailableError","httpStatus":503,"severity":"error","filePath":"server/_shared/required-seed.ts","lineNumber":18,"sourceCode":"import { logCacheReadError, readCachedJson } from './redis';\n\nexport class SeedUnavailableError extends Error {\n  readonly statusCode = 503;\n\n  constructor(key: string) {\n    super(`Seed unavailable: ${key}`);\n    this.name = 'SeedUnavailableError';\n  }\n}\n\nexport async function readRequiredSeed<T>(\n  key: string,\n  decode: (value: unknown) => T | undefined,\n): Promise<T> {\n  const result = await readCachedJson(key, true);\n  if (result.status === 'error') logCacheReadError(key, result.error);\n  if (result.status !== 'hit') throw new SeedUnavailableError(key);\n  const data = decode(result.value);\n  if (data === undefined) throw new SeedUnavailableError(key);\n  return data;\n}\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/server/_shared/required-seed.ts#L1-L23","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst summary = await getHumanitarianSummary(iso3);\n// after\nlet summary;\ntry {\n  summary = await getHumanitarianSummary(iso3);\n} catch (err) {\n  if (err instanceof SeedUnavailableError) {\n    return { summary: null, unavailable: true, seed: err.message };\n  }\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"import { exists } from './seed-check';\n// before calling, ensure the seed metadata exists\nconst seeded = await seedMetaExists(`seed-meta:${key}`); // returns boolean\nif (!seeded) {\n  console.warn(`Seed ${key} not present; run the seed worker first.`);\n}","typeGuard":"function isSeedUnavailableError(err: unknown): err is SeedUnavailableError {\n  return err instanceof SeedUnavailableError;\n}","tryCatchPattern":"try {\n  const data = await readRequiredSeed(key, decode);\n} catch (err) {\n  if (isSeedUnavailableError(err)) {\n    console.error(`Required seed missing or undecodable: ${err.message}`);\n    return fallbackData;\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["cache","redis","seed","data-availability"],"backgroundTag":"cache-miss-required-seed","analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-09-22T01:50:49.965Z","contentChangedAt":"2026-09-22T01:50:49.965Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}