koala73/worldmonitor · error · RpcValidationError

must be an ISO 3166-1 alpha-2 country code.

Error message

must be an ISO 3166-1 alpha-2 country code.

What it means

After selecting the country_code variant, get-five-factor-scorecard validates the value against /^[A-Z]{2}$/ (ISO 3166-1 alpha-2). Anything else — lowercase codes, 3-letter alpha-3 codes, full names — throws RpcValidationError on field country_code. The internal scorecard API expects the strict two-letter uppercase form.

Source

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

    annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
    _coverageKeys: ['scorecard:five-factor:v1', 'seed-meta:scorecard:five-factor'],
    _execute: async (params, base, context) => {
      const countryCode = argStr(params.country_code).trim().toUpperCase();
      const preset = argStr(params.preset).trim().toUpperCase();
      const members = Array.isArray(params.members) ? params.members : [];
      const selectors = Number(countryCode.length > 0) + Number(preset.length > 0) + Number(members.length > 0);
      if (selectors !== 1) {
        throw new RpcValidationError('get-five-factor-scorecard', [{
          field: 'selection',
          description: 'provide exactly one of country_code, preset, or members.',
        }]);
      }

      const q = new URLSearchParams();
      let path: string;
      if (countryCode) {
        if (!/^[A-Z]{2}$/.test(countryCode)) {
          throw new RpcValidationError('get-five-factor-scorecard', [{
            field: 'country_code',
            description: 'must be an ISO 3166-1 alpha-2 country code.',
          }]);
        }
        path = '/api/scorecard/v1/get-five-factor-scorecard';
        q.set('countryCode', countryCode);
      } else {
        path = '/api/scorecard/v1/get-bloc-scorecard';
        if (preset) q.set('preset', preset);
        else members.forEach((member) => q.append('members', String(member)));
      }

      const url = `${base}${path}?${q.toString()}`;
      const auth = await buildAuthHeaders(context, 'GET', url, null);
      const res = await fetch(url, {
        headers: { ...auth, 'User-Agent': 'worldmonitor-mcp-edge/1.0' },
        signal: AbortSignal.timeout(8_000),
      });

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Normalize the input to a two-letter uppercase ISO 3166-1 alpha-2 code before calling ('DEU' -> 'DE', 'germany' -> 'DE').
  2. Reuse the registry's resolveCountryCode helper (as requireCountryCode does) to convert names/aliases to alpha-2 client-side.
  3. Validate with /^[A-Z]{2}$/ in the caller before dispatching the RPC.
  4. For scorecard queries on non-ISO entities, switch to the preset or members selector instead.

Example fix

// before
callTool('get-five-factor-scorecard', { country_code: 'DEU' })
// after
const cc = resolveCountryCode('DEU'); // 'DE'
callTool('get-five-factor-scorecard', { country_code: cc })
Defensive patterns

Strategy: validation

Validate before calling

function isAlpha2Country(v: unknown): v is string {
  return typeof v === 'string' && /^[A-Z]{2}$/.test(v);
}
if (!isAlpha2Country(params.country_code)) throw new Error('country_code must be ISO 3166-1 alpha-2, e.g. "DE"');

Type guard

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

Try / catch

try {
  return await callTool('get-five-factor-scorecard', { country_code: cc });
} catch (err) {
  if (err instanceof RpcValidationError && err.fields?.[0]?.field === 'country_code') {
    const fixed = resolveCountryCode(cc);
    if (fixed) return await callTool('get-five-factor-scorecard', { country_code: fixed });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling get-five-factor-scorecard with country_code values like 'deu', 'DEU', 'Germany', 'D', or '' that survived the selector check but fail the alpha-2 regex.

Common situations: Agents emitting alpha-3 codes (ISO 3166-1 alpha-3) or FIPS codes; frontend inputs not normalized to uppercase; passing a human-readable country name because the selector check allowed it through as the single selector.

Related errors


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