koala73/worldmonitor · error · SeedUnavailableError
Seed unavailable
Error message
Seed unavailable: ${key} What it means
The top-level SeedUnavailableError variant whose message includes the actual Redis key. It is thrown from getStoredStockAnalysisHistory when any per-symbol seed read fails (missing index, missing items, non-string values, or unparsable/non-object snapshots). The message names the offending index key so operators can inspect that exact key.
Solutions
- Read the key name from the error message and inspect it directly (EXISTS/TYPE/ZCARD) in Redis.
- Run the premium stock analysis seeder for the affected symbols.
- If keys expire, adjust TTLs or add a periodic re-seed job.
- Wrap the history handler to return an empty/degraded result with a seed-status health signal if the dashboard should render without seed data.
Example fix
// before: handler propagates SeedUnavailableError to the client
return getStoredStockAnalysisHistory(req.symbols, limit, includeNews);
// after: degrade gracefully with logged seed status
try {
return await getStoredStockAnalysisHistory(req.symbols, limit, includeNews);
} catch (e) {
if (e instanceof SeedUnavailableError) {
logger.warn('seed unavailable', { key: e.message });
return { analyses: {}, seedStatus: 'unavailable' };
}
throw e;
} Defensive patterns
Strategy: fallback
Validate before calling
// pre-flight seed health probe const healthy = await Promise.all(symbols.map(s => redis.exists(analysisHistoryIndexKey(s, includeNews))));
Try / catch
try {
out = await getStoredStockAnalysisHistory(symbols, limit, includeNews);
} catch (e) {
if (e instanceof SeedUnavailableError) {
metrics.seedUnavailable(e.message);
out = Object.fromEntries(symbols.map(s => [s, []]));
} else throw e;
} Prevention
- Run the seeder as part of deployment, before the API accepts traffic.
- Export a seed-status health key and alert on 'unavailable'.
- Log the key name from the error message to speed up diagnosis.
When it happens
Trigger: Any call to history (getStoredStockAnalysisHistory) where at least one requested symbol's analysis seed data is missing or corrupt in Redis; the Promise.all rejects with the message 'Seed unavailable: <indexKey>'.
Common situations: Fresh Redis instance without seeding; expired/evicted keys; seeder not run for newly requested symbols; Upstash REST errors; version-skewed key names between seeder and API.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/ae613172c3bb7cb7.
Report an issue: GitHub.
Appendix: source
Thrown at server/worldmonitor/market/v1/premium-stock-store.ts:172
if (index.length !== 1 || index[0]?.error || !Array.isArray(ids)
|| !ids.every(id => typeof id === 'string')) throw new SeedUnavailableError(indexKey);
if (ids.length === 0) {
out[symbol] = [];
return;
}
const records = await runRedisPipeline(ids.map(id => ['GET', analysisItemKey(String(id))]));
if (records.length !== ids.length) throw new SeedUnavailableError(indexKey);
out[symbol] = records.flatMap(record => {
if (record.error) throw new SeedUnavailableError(indexKey);
if (record.result === null) return [];
if (typeof record.result !== 'string') throw new SeedUnavailableError(indexKey);
let snapshot: AnalyzeStockResponse;
try {
snapshot = JSON.parse(record.result);
} catch {
throw new SeedUnavailableError(indexKey);
}
if (!snapshot || typeof snapshot !== 'object') throw new SeedUnavailableError(indexKey);
return snapshot.available ? [snapshot] : [];
}).sort(compareAnalysisDesc);
}));
return out;
}
export async function storeHistoricalBacktestAnalysisRecords(
snapshots: AnalyzeStockResponse[],
): Promise<void> {
const commands: Array<Array<string | number>> = [];
const touchedSymbols = new Set<string>();
for (const snapshot of snapshots) {
const record = normalizeLedgerRecord(snapshot);
if (!record) continue;
const indexKey = backtestLedgerIndexKey(record.symbol);View on GitHub (pinned to e586b8b4b8)