koala73/worldmonitor · error · McpSourceUnavailableError
Seeded world brief unavailable
Error message
Seeded world brief unavailable (${result.reason}) What it means
McpSourceUnavailableError thrown in get_world_brief (api/mcp/registry/rpc-tools.ts:1007): the bootstrap endpoint call succeeded but projectSeededWorldBrief rejected the insights payload. The parenthesized reason comes from the projector and is one of: malformed-snapshot (insights not a record), empty-brief, status-not-ok, no-headlines, missing-sources, malformed-sources. The error records 'news:insights:v1' as the unavailable input with no failed reads — this is a data-quality/seed problem, not a transport failure. If raw insights arrived as a JSON string that failed to parse, it is also normalized to null first.
Solutions
- Read the reason in the message: 'status-not-ok'/'empty-brief'/'no-headlines' point at the producer writing a degenerate snapshot — re-run or fix the insights producer
- Hit GET /api/infrastructure/v1/get-bootstrap-data and inspect data.insights to see the raw payload that failed projection
- If insights is a string, confirm it is valid JSON — an unparseable string is normalized to null and lands here as malformed/empty
- Re-seed news:insights:v1 with a well-formed snapshot once the producer is healthy
Defensive patterns
Strategy: retry
Validate before calling
// Pre-check the seeded brief shape via the bootstrap endpoint
const boot = await fetch('https://<host>/api/infrastructure/v1/get-bootstrap-data').then(r => r.json());
const insights = typeof boot?.data?.insights === 'string'
? JSON.parse(boot.data.insights) : boot?.data?.insights;
const briefOk = insights?.status === 'ok' && Array.isArray(insights?.headlines) && insights.headlines.length > 0;
if (!briefOk) defer('seeded world brief is degenerate'); Type guard
function isSeededBriefUnavailable(e) {
return e?.name === 'McpSourceUnavailableError'
&& /Seeded world brief unavailable \((malformed-snapshot|empty-brief|status-not-ok|no-headlines|missing-sources|malformed-sources)\)/.test(e?.message ?? '');
} Try / catch
try {
return await client.callTool('get_world_brief', {});
} catch (e) {
if (isSeededBriefUnavailable(e)) {
const reason = e.message.match(/\((.*)\)\$/)?.[1];
if (reason === 'malformed-snapshot') throw e; // producer bug — escalate, no retry
return retryAfter(insightsProducerCadenceMs); // degenerate seed — next cycle may fix it
}
throw e;
} Prevention
- Have the insights producer self-check status==='ok', non-empty headlines, and 1-12 sources before writing
- Monitor news:insights:v1 freshness on /api/health
- Parse the reason code out of the message — it selects retry vs escalate
When it happens
Trigger: Calling get_world_brief when the seeded insights snapshot exists but is empty, has status != 'ok', has no headlines, or its sources array is missing/malformed (>12 entries counts as malformed). Also when insights was stored as an unparseable string.
Common situations: Insights producer ran but wrote an empty/brief-less snapshot (upstream news pipeline down at write time). Stale seed from before a format change. New environment seeded with a placeholder snapshot. Producer writing more than 12 source items violating the bounded contract.
Related errors
- Could not resolve to a country.
- country must be an ISO 3166-1 alpha-2 country code, e.g…
- get-china-decision-signals returned an invalid canonical…
- get-china-decision-signals returned no canonical payload
- get-country-intel-brief HTTP
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-08-21).
Data as JSON: /api/errors/ec962e3301ea4c25.
Report an issue: GitHub.
Appendix: source
Thrown at api/mcp/registry/rpc-tools.ts:1432
operation: 'bootstrap-insights',
tool: 'get_world_brief',
auth: context,
execution,
});
type BootstrapPayload = { data?: { insights?: unknown }; missing?: string[] };
const bootstrap = await insightsRes.json() as BootstrapPayload;
const rawInsights = bootstrap.data?.insights;
let insights: unknown = rawInsights;
if (typeof rawInsights === 'string') {
try {
insights = JSON.parse(rawInsights);
} catch {
insights = null;
}
}
const result = projectSeededWorldBrief(insights);
if ('reason' in result) {
throw new McpSourceUnavailableError(
`Seeded world brief unavailable (${result.reason})`,
['news:insights:v1'],
[],
);
}
return result.value;
},
_apiPaths: ['GET /api/infrastructure/v1/get-bootstrap-data'],
},
{
name: 'get_country_brief',
// Two downstream fetches (brief + news digest for grounding).
_weight: 3,
_outputBudgetBytes: 65536,
description: 'AI-generated per-country intelligence brief. Produces an LLM-analyzed geopolitical and economic assessment for the given country. Supports analytical frameworks for structured lenses. Returns groundingStories alongside sources: the digest articles used to ground the brief, each with corroborationCount, mentionCount, and lifecycle storyPhase, so an agent can weigh how well-corroborated the underlying reporting is. When the news digest is serving retained (stale) content, that grounding is DROPPED and the brief is generated without it; pass allow_stale=true to ground on the retained snapshot instead. Either way the digestCoverage block reports what the grounding was.',
inputSchema: {
type: 'object',
properties: {View on GitHub (pinned to e586b8b4b8)