koala73/worldmonitor · error · RpcValidationError

Could not resolve to a country.

Error message

Could not resolve ${JSON.stringify(echoCountryInput(raw))} to a country. ${COUNTRY_ARG_HINT}

What it means

requireCountryCode() resolves a caller-supplied country argument (name, code, alias) via resolveCountryCode(); if resolution fails it throws RpcValidationError with a field-level description including the echoed (safe, JSON-stringified) input and COUNTRY_ARG_HINT. It fails loudly so an agent can self-correct its arguments.

Solutions

  1. Pass a valid ISO 3166-1 alpha-2 code (e.g. "CH", "US") — the most reliable form.
  2. Use the exact country name or alias supported by resolveCountryCode; consult COUNTRY_ARG_HINT in the error message for accepted formats.
  3. Trim whitespace and fix casing (resolution is typically case-insensitive but exact spelling matters).
  4. If the entity genuinely has no country code (e.g. an EU-wide query), use the tool's non-country variant or preset parameter instead.

Example fix

// before
callTool('get-country-brief', { country_code: 'Swiss' })
// after
callTool('get-country-brief', { country_code: 'CH' })
Defensive patterns

Strategy: validation

Validate before calling

const resolved = resolveCountryCode(raw);
if (!resolved) {
  throw new Error(`"${raw}" is not a recognized country; pass an ISO 3166-1 alpha-2 code like "CH"`);
}

Type guard

function isAlpha2(v: unknown): v is string {
  return typeof v === 'string' && /^[A-Za-z]{2}$/.test(v);
}

Try / catch

try {
  const cc = requireCountryCode(raw, 'get-country-brief');
} catch (err) {
  if (err instanceof RpcValidationError) {
    // inspect err.fields / description; retry once with a normalized alpha-2 code
  } else throw err;
}

Prevention

When it happens

Trigger: Calling any MCP RPC tool whose handler calls requireCountryCode (directly or via countryCode()/code()) with a raw value that resolveCountryCode cannot map — misspelled country names, lowercase or non-alpha-2 codes, unknown aliases, non-string types like numbers or objects.

Common situations: An LLM agent passing 'Swiss' or 'CHN'-style typo codes; passing a numeric ISO 3166-1 numeric code; passing localized country names; passing null/undefined when the parameter was optional upstream.

Related errors


AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-01). Data as JSON: /api/errors/4f948e179af6455a. Report an issue: GitHub.

Appendix: source

Thrown at api/mcp/registry/rpc-tools.ts:90

  staleAgeSeconds?: number;
  staleReason?: string;
  attemptedAt?: string;
};

// Corroboration for the country brief cannot ride on `sources`: that array is
// the proto BriefSource shape (title/source/url/publishedAt) returned by the
// gateway, so widening it would be a proto change, and on the common path the
// server-side sources win anyway. A sibling field keeps the citation list
// exactly as it is. (#4925 item 3)
type McpBriefGroundingStory = {
  title: string;
  source: string;
  url?: string;
  publishedAt?: string;
  corroborationCount: number;
  mentionCount?: number;
  storyPhase?: string;
};

// Keep the optional grounding copy smaller than the primary citation list.
// An oversized URL is omitted rather than truncated because a clipped URL is
// no longer a valid citation target. The primary `sources` field remains the
// canonical citation surface.
const MAX_COUNTRY_BRIEF_GROUNDING_URL_LENGTH = 2_000;

function clipBriefText(value: unknown, maxLen: number): string {
  if (typeof value !== 'string') return '';
  const text = value.replace(/\s+/g, ' ').trim();
  return text.length > maxLen ? `${text.slice(0, maxLen - 1).trim()}...` : text;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return !!value && typeof value === 'object' && !Array.isArray(value);
}

/**

View on GitHub (pinned to e586b8b4b8)