koala73/worldmonitor · error · RpcValidationError

Could not resolve ${JSON.stringify(echoCountryInput(raw))} t

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.

Source

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

// not pick freely.

/**
 * Resolve a `country_code` tool argument, or throw the same structured 400 the
 * downstream proto would have raised — reaching the agent as JSON-RPC -32602
 * with `error.data.violations[]`.
 *
 * The argument comes from an LLM, so it arrives as alpha-2, alpha-3, a country
 * name, or an alias interchangeably. It was previously coerced with
 * `.toUpperCase().slice(0, 2)`, which is silently wrong rather than lossy: the
 * proto only enforces `^[A-Z]{2}$`, so a truncated NAME passes validation and
 * answers for a different country — `Iraq` was served as Iran, `China` as
 * Switzerland (WORLDMONITOR-Y2). Failing loudly on the genuinely unresolvable
 * remainder is what lets an agent correct itself.
 */
function requireCountryCode(raw: unknown, operation: string): string {
  const resolved = resolveCountryCode(raw);
  if (resolved) return resolved;
  throw new RpcValidationError(operation, [{
    field: 'country_code',
    description: `Could not resolve ${JSON.stringify(echoCountryInput(raw))} to a country. ${COUNTRY_ARG_HINT}`,
  }]);
}

type DigestItemForBrief = {
  title?: string;
  snippet?: string;
  source?: string;
  link?: string;
  url?: string;
  publishedAt?: string | number;
  pubDate?: string | number;
  date?: string | number;
  // Emitted by toProtoItem in server/worldmonitor/news/v1/list-feed-digest.ts
  // for every digest item, and dropped on the way to an agent until #4925.
  corroborationCount?: number;
  storyMeta?: {

View on GitHub (pinned to 9361220cc0)

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@9361220cc0 (2026-09-01). Data as JSON: /api/errors/4f948e179af6455a. Report an issue: GitHub.