koala73/worldmonitor · error · Error
cache_all_null
Error message
cache_all_null
What it means
Thrown inside the country-markets MCP tool path when every Redis data read (overview, categories, movers, etc. for a given country_code) returned null or undefined. This is a contract-parity guard matching the cache-tool executeTool path: if ALL data keys are null the response is degenerate (Redis transient, stampede, or pre-seed), so it throws a plain Error to surface as a tool-execution failure in dispatchToolsCall. For Pro callers the already-reserved billing slot stays charged because the tool did execute.
Source
Thrown at api/mcp/registry/rpc-tools.ts:1224
{ key: `seed-meta:consumer-prices:categories:${code}:30d`, maxStaleMin: 1500 },
{ key: `seed-meta:consumer-prices:movers:${code}:30d`, maxStaleMin: 1500 },
{ key: `seed-meta:consumer-prices:spread:${code}`, maxStaleMin: 1500 }, // producer's actual key shape
{ key: `seed-meta:consumer-prices:freshness:${code}`, maxStaleMin: 1500 },
];
const [dataResults, metaResults] = await Promise.all([
Promise.all(dataKeys.map((k) => readJsonFromUpstash(k))),
Promise.all(freshnessChecks.map((c) => readJsonFromUpstash(c.key))),
]);
// F6 contract parity with the cache-tool path (executeTool, ~line 1139):
// if every data read is null/undefined, this is a degenerate-empty
// response (Redis transient / stampede / pre-seed). Throw so
// dispatchToolsCall reports a normal tool-execution failure. For Pro
// callers the already-reserved slot stays charged because the tool has
// executed.
if (dataResults.every((v: unknown) => v === null || v === undefined)) {
throw new Error('cache_all_null');
}
const { cached_at, stale } = evaluateFreshness(freshnessChecks, metaResults);
return {
cached_at,
stale,
country_code: code,
data: {
overview: dataResults[0],
categories: dataResults[1],
movers: dataResults[2],
retailerSpread: dataResults[3],
freshness: dataResults[4],
},
};
},
// Hybrid tool covers the consumer-prices domain via direct Redis readsView on GitHub (pinned to ffec79ac33)
Solutions
- Verify the market data keys exist in Redis for that country_code — check GET /api/health for the relevant market seed-meta entries.
- Retry after the market data cadence — stampede and transient null conditions resolve on TTL refresh.
- Try a different country_code known to be seeded (e.g. 'US') to confirm whether the issue is country-specific or systemic.
- If systemic, verify the market seeder (Yahoo Finance / provider) is running and the data keys are being written.
Defensive patterns
Strategy: retry
Validate before calling
// Verify market data is seeded for the country before calling
const health = await fetch('/api/health').then(r => r.json());
const marketKeys = health.coverage ? Object.keys(health.coverage).filter(k => k.includes(`market:${countryCode}`)) : [];
if (marketKeys.length === 0) {
throw new Error(`No market data seeded for ${countryCode}; try a different country or wait for seeder`);
} Type guard
function isCacheAllNullError(e: unknown): boolean {
return e instanceof Error && e.message === 'cache_all_null';
} Try / catch
try {
const snapshot = await callMcpTool('get_market_snapshot', { country_code: 'US' });
} catch (e) {
if (e instanceof Error && e.message === 'cache_all_null') {
// Degenerate empty — retry after seeder cycle, or try a known-seeded country
await backoffRetry(30_000);
} else throw e;
} Prevention
- Test with a known-seeded country (e.g. 'US') to distinguish country-specific gaps from systemic outages.
- Monitor market seed-meta keys in GET /api/health.
- Be aware that for Pro callers the billing slot is already charged even on this failure — avoid rapid retries.
When it happens
Trigger: Calling the country markets snapshot tool for a country_code where all market data keys are null in Redis — before the market seeder has populated that country, after a Redis flush, or during a stampede where all concurrent cold reads see null. The freshness metadata reads may still succeed (seed-meta keys exist), but the data keys themselves are absent.
Common situations: A country_code that has never been seeded (the market seeder covers a specific symbol set); a Redis flush or eviction that dropped the data keys but left seed-meta keys; a weekend/holiday where the market data producer did not run and TTLs expired.
Related errors
- No event feeds are available for exposure enrichment
- No digest input feeds are available
- No hotspot-escalation input feeds are available
- The submarine-cable catalog is unavailable
- Feed digest unavailable for ${variant}/en
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/ae9161d16590d4ba.
Report an issue: GitHub.