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

  1. 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
  2. Hit GET /api/infrastructure/v1/get-bootstrap-data and inspect data.insights to see the raw payload that failed projection
  3. If insights is a string, confirm it is valid JSON — an unparseable string is normalized to null and lands here as malformed/empty
  4. 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

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


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)